javascript是一门单线程的非阻塞的脚本语言。单线程意味着javascript在执行代码的任什么时候候,都只有一个主线程来处理全部的任务。javascript
那么javascript引擎是如何实现这一点的呢?java
由于事件循环(event loop)。先上图:git
图片解读:github
Event Table
并注册函数Event Table
会将这个函数移入Event Queue
中Event Queue
读取对应的函数,进入主线程执行Event Loop(事件循环)
。咱们来一个简单的例子来讲明下:promise
console.log('1');
setTimeout(() => {
console.log('2');
}, 0)
console.log('3');
复制代码
上面的代码将输出下面的结果:bash
1
3
2
复制代码
由于setTimeout是一个异步的任务,因此会在最后才执行。异步
那么,咱们来个复杂点的例子:函数
console.log('1');
setTimeout(() => {
console.log('2')
}, 1000);
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('3');
}, 0);
console.log('4');
resolve();
console.log('5');
}).then(() => {
console.log('6');
});
console.log('7');
复制代码
上面的代码输出的结果是:oop
1
4
5
7
6
3
2
复制代码
看到这代码的时候是否是有些蒙圈?在咱们揭开谜底以前,先来了解下微任务和宏任务。post
微任务和宏任务都是异步的任务,他们都属于队列,主要区别是它们的执行顺序--微任务会比宏任务先执行。
宏任务包含有:setTimeout, setInterval, setImmediate, I/O, UI rendering
微任务包含有:process.nextTick, promise.then, MutationObserver
嗯~回到上面的代码,以下:
console.log('1');
setTimeout(() => {
console.log('2')
}, 1000);
new Promise((resolve, reject) => {
setTimeout(() => {
console.log('3');
}, 0);
console.log('4');
resolve();
console.log('5');
}).then(() => {
console.log('6');
});
console.log('7');
复制代码
在执行到new Promise
的时候会立马新建一个promise对象并当即执行
。因此会输出 1,4,5
,而then则会在Event Table
中注册成回调函数并放在微任务队列中,而两个setTimeout(输出3)和setTimeout(输出2,1s后完成的啊)
会被前后注册成回调函数并放在宏任务队列中。
理解了上面的一些原理以后,咱们再来练下手...
console.log(1)
process.nextTick(() => {
console.log(8)
setTimeout(() => {
console.log(9)
})
})
setTimeout(() => {
console.log(2)
new Promise(() => {
console.log(11)
})
})
let promise = new Promise((resolve,reject) => {
setTimeout(() => {
console.log(10)
})
resolve()
console.log(4)
})
fn()
console.log(3)
promise.then(() => {
console.log(12)
})
function fn(){
console.log(6)
}
复制代码
获得的结果是:
1
4
6
3
8
12
2
11
10
9
复制代码
客官能够画下图整理下思路,而后代码运行验证一下啊💨
文章首发javascript事件循环机制,更多的内容,请戳个人博客进行了解,能留个star就更好了💨