看不看得懂先来两张图:
浏览器运行机制:
上图中“js引擎线程,定时器触发器线程,事件出发线程”共同作用 的 js执行机制如下图
代码拿去跑跑就大致掌握了(实践出真知)
//层 也就是执行上下文
//同步输出 也就是进入执行栈js线程(注:宏任务以及所有的输出都属于同步输出)
// 在浏览器环境运行 请注释掉 process.nextTick 和 setImmediate
/**
* JS所谓的“单线程”只是指主线程只有一个,并不是整个运行环境都是单线程
JS的异步靠底层的多线程实现
不同的异步API对应不同的实现线程
异步线程与主线程通讯靠的是Event Loop
异步线程完成任务后将其放入任务队列
主线程不断轮询任务队列,拿出任务执行
任务队列有宏任务队列和微任务队列的区别
微任务队列的优先级更高,所在执行上下文所有同步任务+微任务处理完后,才会处理下一个宏任务
Promise是微任务
Node.js的Event Loop跟浏览器的Event Loop不一样,他是分阶段的
setImmediate和setTimeout(fn, 0)哪个回调先执行,需要看他们本身在哪个阶段注册的,如果在定时器回调或者I/O回调里面,setImmediate肯定先执行。如果在最外层或者setImmediate回调里面,哪个先执行取决于当时机器状况。
process.nextTick不在Event Loop的任何阶段,他是一个特殊API,他会立即执行,然后才会继续执行Event Loop
*/
/**
* macro-task大概包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
micro-task大概包括: process.nextTick, Promise, Object.observe(已废弃), MutationObserver(html5新特性)
*/
console.log('主任务 script层 入栈执行 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
setTimeout(function () {
console.log('宏任务 setTimeout1层 入栈执行 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
console.log('宏任务 同步输出 setTimeout1(主函数)');
new Promise(function (resolve) {
console.log('同步输出 setTimeout1 promise1构造函数');
resolve();
}).then(function () {
console.log('微任务@ setTimeout1 promise1.then')
console.log("宏任务 setTimeout1层 以及本层所有微任务 执行完毕!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
})
setTimeout(function () {
console.log('宏任务 setTimeout11层 入栈执行 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
console.log('宏任务 同步输出 setTimeout11(主函数)');
new Promise(function (resolve) {
console.log('同步输出 setTimeout11 promise11构造函数');
resolve();
}).then(function () {
console.log('微任务@ setTimeout11 promise11.then')
}).then(function () {
console.log('我是微任务@promise11产生的微任务,也要执行完才可进行下一个宏任务哦')
console.log("宏任务 setTimeout11层 以及本层所有微任务 执行完毕!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
})
})
})
// setImmediate(function () {
// console.log('immediate1');
// process.nextTick(function () {
// console.log('immediate1_nextTick');
// })
// new Promise(function (resolve) {
// console.log('immediate1_promise');
// resolve();
// }).then(function () {
// console.log('immediate1_then')
// })
// })
setTimeout(function () {
console.log('宏任务 setTimeout2层 入栈执行 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
new Promise(function (resolve) {
console.log('同步输出 setTimeout2 promise2构造函数');
resolve();
}).then(function () {
console.log('微任务@ setTimeout2 promise2.then')
console.log("宏任务 setTimeout2层 以及本层所有微任务 执行完毕!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
})
setTimeout(function () {
console.log('宏任务 setTimeout22层 入栈执行 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
console.log('宏任务 同步输出 setTimeout22(主函数)');
new Promise(function (resolve) {
console.log('同步输出 setTimeout22 promise22构造函数');
resolve();
}).then(function () {
console.log('微任务@ setTimeout22 promise22.then@')
}).then(function () {
console.log('我是微任务@promise22产生的微任务,也要执行完才可进行下一个宏任务哦')
console.log("宏任务 setTimeout22层 以及本层所有微任务 执行完毕!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
})
})
})
// setImmediate(function () {
// console.log('immediate2');
// process.nextTick(function () {
// console.log('immediate2_nextTick');
// })
// new Promise(function (resolve) {
// console.log('immediate2_promise');
// resolve();
// }).then(function () {
// console.log('immediate2_then')
// })
// })
new Promise(function (resolve) {
console.log('主任务 script层 同步输出 promise01构造函数');
resolve();
}).then(function () {
console.log('微任务@ promise01.then')
})
// process.nextTick(function () {
// console.log('glob1_nextTick');
// })
//由此可见 nodejs中 process.nextTick 的异步优先级要比 promise.then 高
new Promise(function (resolve) {
console.log('主任务 script层 同步输出 promise02构造函数');
resolve();
}).then(function () {
console.log('微任务@ promise02.then')
console.log("主任务 script层 以及本层所有微任务 执行完毕!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
})
// process.nextTick(function () {
// console.log('glob2_nextTick');
// })
那么,根据打印的结果,我理解的 Promise 的执行逻辑是:
1. 按同步的运行顺序,执行 Promise 的构造函数
2. 将所有 Promise 构造函数后的第一个 then() 函数放入异步队列中(如果存在的话)
3.1 将所有 Promise 构造函数后的第二个 then() 函数放入异步队列中(如果存在的话)
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve, reject) => {
console.log(2)
resolve('p1')
new Promise((resolve, reject) => {
console.log(3)
setTimeout(() => {
resolve('setTimeout2')
console.log(4)
}, 0)
resolve('p2')
}).then(data => {
console.log(data)
})
setTimeout(() => {
resolve('setTimeout1')
console.log(5)
}, 0)
}).then(data => {
console.log(data)
})
console.log(6)
//结果 : 2,3,6,p1,p2,1,4,5
参考文献地址:
setTimeout和setImmediate到底谁先执行,本文让你彻底理解Event Loop__蒋鹏飞的博客-CSDN博客
https://www.jianshu.com/p/12b9f73c5a4f
这一次,彻底弄懂 JavaScript 执行机制 - 掘金
在此感谢大佬们的分享,受教!