javascript是一门单线程的非阻塞的脚本语言。单线程意味着javascript在执行代码的任何时候,都只有一个主线程来处理所有的任务。
那么javascript引擎是如何实现这一点的呢?
因为事件循环(event loop)。先上图:

图片解读:
- 同步和异步任务分别进入不同的执行场所,同步的进入主线程,异步的进入
Event Table并注册函数 - 当指定的事情完成时(重点),
Event Table会将这个函数移入Event Queue中 - 主线程内的任务执行完毕为空,会去
Event Queue读取对应的函数,进入主线程执行 - 上述的过程会不断的重复,也就是常常说的
Event Loop(事件循环)。
简单例子
我们来一个简单的例子来说明下:
1console.log('1'); 2setTimeout(() => { 3 console.log('2'); 4}, 0) 5console.log('3'); 6复制代码
上面的代码将输出下面的结果:
11 23 32 4复制代码
因为setTimeout是一个异步的任务,所以会在最后才执行。
那么,我们来个复杂点的例子:
复杂例子
1 console.log('1'); 2 setTimeout(() => { 3 console.log('2') 4 }, 1000); 5 new Promise((resolve, reject) => { 6 setTimeout(() => { 7 console.log('3'); 8 }, 0); 9 console.log('4'); 10 resolve(); 11 console.log('5'); 12 }).then(() => { 13 console.log('6'); 14 }); 15 console.log('7'); 16复制代码
上面的代码输出的结果是:
11 24 35 47 56 63 72 8复制代码
看到这代码的时候是不是有些蒙圈?在我们揭开谜底之前,先来了解下微任务和宏任务。
微任务和宏任务
微任务和宏任务都是异步的任务,他们都属于队列,主要区别是它们的执行顺序--微任务会比宏任务先执行。
宏任务包含有:setTimeout, setInterval, setImmediate, I/O, UI rendering
微任务包含有:process.nextTick, promise.then, MutationObserver
嗯~回到上面的代码,如下:
1 console.log('1'); 2 setTimeout(() => { 3 console.log('2') 4 }, 1000); 5 new Promise((resolve, reject) => { 6 setTimeout(() => { 7 console.log('3'); 8 }, 0); 9 console.log('4'); 10 resolve(); 11 console.log('5'); 12 }).then(() => { 13 console.log('6'); 14 }); 15 console.log('7'); 16复制代码
在执行到new Promise的时候会立马新建一个promise对象并立即执行。所以会输出 1,4,5,而then则会在Event Table中注册成回调函数并放在微任务队列中,而两个setTimeout(输出3)和setTimeout(输出2,1s后完成的啊)会被先后注册成回调函数并放在宏任务队列中。
理解了上面的一些原理之后,我们再来练下手...
1console.log(1) 2process.nextTick(() => { 3 console.log(8) 4 setTimeout(() => { 5 console.log(9) 6 }) 7}) 8setTimeout(() => { 9 console.log(2) 10 new Promise(() => { 11 console.log(11) 12 }) 13}) 14let promise = new Promise((resolve,reject) => { 15 setTimeout(() => { 16 console.log(10) 17 }) 18 resolve() 19 console.log(4) 20}) 21fn() 22console.log(3) 23promise.then(() => { 24 console.log(12) 25}) 26function fn(){ 27 console.log(6) 28} 29复制代码
得到的结果是:
11 24 36 43 58 612 72 811 910 109 11复制代码
客官可以画下图整理下思路,然后代码运行验证一下啊💨
参考&后话
文章首发javascript事件循环机制,更多的内容,请戳我的博客进行了解,能留个star就更好了💨
.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
本文同步分享在 博客“Jimmy”(JueJin)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。