Eventloop机制是Javascript实现伪“多线程”的关键所在。这一部分也是面试常常会被问到的问题,做个笔记以备查询。
JavaScript的执行机制
首先明确一点,JavaScript是一个单线程语言。所有的任务在JavaScript中都被划分为以下三类之一:
- 同步任务
- 异步宏任务
- 异步微任务
JavaScript通过频繁地切换这些任务,来实现异步任务。

“一个不靠谱码农的笔记集合”
发布于 2022-03-11 44 次阅读
Eventloop机制是Javascript实现伪“多线程”的关键所在。这一部分也是面试常常会被问到的问题,做个笔记以备查询。
首先明确一点,JavaScript是一个单线程语言。所有的任务在JavaScript中都被划分为以下三类之一:
JavaScript通过频繁地切换这些任务,来实现异步任务。
从整体的执行机制而言,JavaScript按照以下顺序处理手头的任务:
setTimeout
, setInterval
, setImmediate
Promise
process.nextTick
(node.js)Object.observe
MutationObserver
Event Queue中的异步事件按照以下流程图执行:
console.log(1)
new Promise((resolve, reject) => {
console.log(2)
resolve()
}).then(res => {
console.log(3)
})
console.log(4)
输出:1 2 4 3
解释:
console.log(1)
,输出 1
。new Promise
,立即执行console.log(2)
输出 2
,并且把.then
的回调函数在Event Queue中注册。console.log(4)
,输出 4
。console.log(3)
,输出 3
。console.log('start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
new Promise((resolve) => {
console.log('promise')
resolve()
}).then(() => {
console.log('then1')
}).then(() => {
console.log('then2')
})
console.log('end')
输出:start promise end then1 then2 setTimeout
解释:
console.log(start)
,输出 start
。setTimeout
,将回调放入宏任务队列。new Promise
,立即执行console.log(promise)
输出 promise
,并且把两个.then
的回调函数放到微任务队列。console.log(end)
,输出 end
。console.log(then1, then2)
,输出 then1, then2
。console.log(setTimeout)
,输出setTimeout
。console.log('start')
setTimeout(() => {
console.log('setTimeout')
new Promise((resolve) => {
console.log('promise2')
resolve()
}).then( () => {
console.log('then3')
})
}, 0)
new Promise((resolve) => {
console.log('promise1')
resolve()
}).then(() => {
console.log('then1')
}).then(() => {
console.log('then2')
})
console.log('end')
输出:start promise1 end then1 then2 setTimeout promise2 then3
解释:
console.log(start)
,输出 start
。setTimeout
,将回调放入宏任务队列。new Promise
,立即执行console.log(promise1)
输出 promise1
,并且把两个.then
的回调函数放到微任务队列。console.log(end)
,输出 end
。console.log(then1, then2)
,输出 then1, then2
。console.log(setTimeout)
,输出setTimeout
。new Promise
,立即执行console.log('promise 2')
输出promise 2
,并把.then
放入微任务队列。console.log(then3)
,输出then3
。console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
输出:1 7 6 8 2 4 3 5 9 11 10 12
解释:
console.log(1)
,输出 1
。setTimeout
,将回调放入宏任务队列。process.nextTick
,将函数放到微任务队列。new Promise
,立即执行console.log(7)
输出 7
,并且把.then
的回调函数放到微任务队列。setTimeout
,将回调放入宏任务队列。6
,8
。setTimeout
宏任务console.log(2)
,输出2
。process.nextTick
,将函数放到微任务队列。new Promise
,立即执行console.log(4)
输出 4
,并且把.then
的回调函数放到微任务队列。3
,5
。setTimeout
宏任务console.log(9)
,输出9
。process.nextTick
,将函数放到微任务队列。new Promise
,立即执行console.log(11)
输出 11
,并且把.then
的回调函数放到微任务队列。10
,12
。最近在处理react-redux的useSelector和useState两个hook结合使用的问题时遇到了相关问题。在同一useEffect里的多次setState,且初始state和终了state一致时,并不会触发其他hook里的相应的dependency。使用new Promise(resolve => setTimeout(resolve, 0))后问题不再出现,就次引发了写下这篇笔记的动力。猜测可能和react的调和机制有关,需要更深入研究react的代码。