js是基于单线程运行的,而一些特定事件又是异步执行的,因此这种单线程+异步的执行方式必定是事件驱动的 而通常浏览器环境下有这样几种线程。css
js引擎线程 (解释执行js代码、用户输入、网络请求)主线程promise
GUI线程 (绘制用户界面、与js主线程是互斥的)先绘制dom再绘制css浏览器
http网络请求线程 (处理用户的get、post等请求,等返回结果后将回调函数推入任务队列)bash
定时触发器线程 (setTimeout、setInterval等待时间结束后把执行函数推入任务队列中)网络
浏览器事件处理线程(将click、mouse等交互事件发生后将这些事件放入事件队列中)数据结构
上一张经典的eventLoop图,了解几个基本概念多线程
那问题就来了,js中task和microTask执行顺序是怎样的dom
因为js是单线程,全部的多线程任务最后都要压入主线程执行栈去执行,如图所示,task会放入回调队列里 由eventLoop取出依次执行。异步
这里能够解释一个小问题,若是多个setTimeout的状况下,执行时间不是特别的精确,setTimeout 它会在延迟时间结束后分配一个新的 task 至 event loop 中,而不是当即执行,因此 setTimeout 的回调函数会等待前面的 task 都执行结束后再运行。函数
说到这里好像尚未microTask什么事,那microTask在何时执行呢,通俗的说,你能够将microTask理解为一个爱插队的大妈,就是在一个task事件结束后,microTask就插入执行栈当即执行,执行顺序是主线程执行栈的队尾插入,callback quene以前
上一段代码吧,来直观的了解一下执行顺序
console.log('start');
setTimeout(function() {
console.log('setTimeout1');
setTimeout(function() {
console.log('setTimeout2');
},0);
console.log('setTimeout3');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('end');
复制代码
最后结果是 1,start 2,end 3,promise1 4,promise2 5,setTimeout1,6,setTimeout3 6,setTimeout2
顺序是,先执行打印start 而后打印edn 这时候microTask (promise)插队进入 打印promise1,promise2, 而后执行setTimeout打印setTimeout1,setTimeout3,这里能够看作
console.log('setTimeout1');
console.log('setTimeout3');
这两句一块儿压入执行栈,
setTimeout(function() {
console.log('setTimeout2');
},0);
复制代码
进入task队列,由EventLoop取出,因此最后执行顺序是 1,start 2,end 3,promise1 4,promise2 5,setTimeout1,6,setTimeout3 6,setTimeout2