前言js引擎不是独立运行的,它运行在宿主环境中,这个环境可以是浏览器、可以是服务器,或者其他硬件设施。所以在浏览器的帮助下,js作为一种单线程语言,可以实现异步操作。浏览器内核是多线程的,几个常驻的线程:渲染引擎线程、js引擎线程、定时触发器线程、事件触发线程、异步http请求线程。并发模型https://developer.mozilla.org…左边的栈存储的是同步任务。右边的堆用来存储声明的变量、对象。下面的队列就是任务队列,一旦某个异步任务有了响应就会被推入队列中。每个异步任务都和一个回调函数相关联。一个js程序的单线程用来执行栈中的同步任务,当所有同步任务执行完毕后,栈被清空,然后读取任务队列中的一个待处理任务,并把相关回调函数压入栈中,单线程开始执行新的同步任务,执行完毕。单线程从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有新的任务,就会等待,直到有新的任务,这就叫任务循环或者事件循环事件循环(Event Loop)事件循环的大致流程如下:主线程执行所有同步任务,形成一个执行栈(并发模型中的stack)。主线程执行同步任务的同时,子线程执行异步任务,并将相应的结果(事件)放入任务队列。一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,把任务队列中事件相应的回调函数压入栈内开始执行。执行回调后,栈空,继续重复第三步,形成一个循环。Microtask与Macrotask(task)Microtask和Macrotask(task)是异步任务的两个分类。macrotasks: setTimeout, setInterval, setImmediate, I/O, UI renderingmicrotasks: process.nextTick, Promises, Object.observe(废弃), MutationObserver事件循环每次只会入栈一个 macrotask任务 ,主线程会先检查 microtasks 队列并完成里面的所有任务后再执行 macrotask(task)。举个栗子:console.log(‘script start’);setTimeout(function() { console.log(‘setTimeout1’);})}, 0);setTimeout(function() { console.log(‘setTimeout2’);}, 0);Promise.resolve().then(function() { console.log(‘promise1’);}).then(function() { console.log(‘promise2’);});console.log(‘script end’);结果是:“script start"“script end"“promise1"“promise2"“setTimeout1"“setTimeout2"可以看到,macrotask是在microtask全部执行后才执行的。再举一个栗子:console.log(‘script start’);setTimeout(function() { console.log(‘setTimout1’); setTimeout(function() { console.log(‘setTimout2’); }, 0); Promise.resolve().then(function() { console.log(‘promise3’); })}, 0);Promise.resolve().then(function() { console.log(‘promise1’);}).then(function() { console.log(‘promise2’);});console.log(‘script end’);结果是:“script start"“script end"“promise1"“promise2"“setTimout1"“promise3"“setTimout2"可以发现,在执行完setTimeout1之后没有继续执行setTimeout2,而是去执行了promise3,这也验证了:每执行一个macrotask任务之前都会执行完当前的microtask队列。注: 代码示例参考链接:https://v.youku.com/v_show/id…