我们还经常遇到setTimeout(fn,0)这样的代码,0秒后执行又是什么意思呢?是不是可以立即执行呢?
答案是不会的,setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,意思就是不用再等多少秒了,只要主线程执行栈内的同步任务全部执行完成,栈为空就马上执行 。举例说明:
//代码1console.log('先执行这里');setTimeout(() => {console.log('执行啦')},0);//代码2console.log('先执行这里');setTimeout(() => {console.log('执行啦')},3000);
代码1的输出结果是:
//先执行这里//执行啦
代码2的输出结果是:
//先执行这里// ... 3s later// 执行啦
关于setTimeout要补充的是,即便主线程为空,0毫秒实际上也是达不到的 。根据HTML的标准,最低是4毫秒 。有兴趣的同学可以自行了解 。
4.又恨又爱的setInterval上面说完了setTimeout,当然不能错过它的孪生兄弟setInterval 。他俩差不多,只不过后者是循环的执行 。对于执行顺序来说,setInterval会每隔指定的时间将注册的函数置入Event Queue,如果前面的任务耗时太久,那么同样需要等待 。
唯一需要注意的一点是,对于setInterval(fn,ms)来说,我们已经知道不是每过ms秒会执行一次fn,而是每过ms秒,会有fn进入Event Queue 。一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就完全看不出来有时间间隔了 。这句话请读者仔细品味 。
5.Promise与process.nextTick(callback)传统的定时器我们已经研究过了,接着我们探究Promise与process.nextTick(callback)的表现 。
Promise的定义和功能本文不再赘述,而process.nextTick(callback)类似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数 。
我们进入正题,除了广义的同步任务和异步任务,我们对任务有更精细的定义:
- macro-task(宏任务):包括整体代码script,setTimeout,setInterval
- micro-task(微任务):Promise,process.nextTick
事件循环的顺序,决定js代码的执行顺序 。进入整体代码(宏任务)后,开始第一次循环 。接着执行所有的微任务 。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务 。听起来有点绕,我们用文章最开始的一段代码说明:
setTimeout(function() {console.log('setTimeout');})new Promise(function(resolve) {console.log('promise');}).then(function() {console.log('then');})console.log('console');
- 这段代码作为宏任务,进入主线程 。
- 先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue 。(注册过程与上同,下文不再描述)
- 接下来遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue 。
- 遇到console.log(),立即执行 。
- 好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行 。
- ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始 。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行 。
- 结束 。
文章插图
我们来分析一段较复杂的代码,看看你是否真的掌握了js的执行机制:
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')})})
第一轮事件循环流程分析如下:- 整体script作为第一个宏任务进入主线程,遇到console.log,输出1 。
- 遇到setTimeout,其回调函数被分发到宏任务Event Queue中 。我们暂且记为setTimeout1 。
- 遇到process.nextTick(),其回调函数被分发到微任务Event Queue中 。我们记为process1 。
- 遇到Promise,new Promise直接执行,输出7 。then被分发到微任务Event Queue中 。我们记为then1 。
推荐阅读
- 玉兰花茶如何鉴别,金银花茶如何贮存
- 杭白菊功效有哪些,菊花茶的功效有哪些
- MacOS上这款8款软件让你效率翻倍!
- 不喜欢 diff 么?试试 Meld 吧
- 玫瑰花茶选购方式,玫瑰花茶到底是什么茶
- 孕妇不可以喝桂花茶,孕妇可以喝菊花茶吗
- 平阴玫瑰花茶的功效与作用,红花茶的作用
- 古树茶花的功效与作用,墨旱莲的功效与作用
- 茉莉龙井茶的功效与作用,茉莉花的功效与作用
- 如果再有人问你数据库的原理,把这篇文章给他