js关于async/await、promise和setTimeout执行顺序

您所在的位置:网站首页 定时器的执行顺序和机制是 js关于async/await、promise和setTimeout执行顺序

js关于async/await、promise和setTimeout执行顺序

2023-06-11 23:51| 来源: 网络整理| 查看: 265

前段时间看到了一道面试题,关于async/await、promise和setTimeout的执行顺序,觉得挺有意思的,记录一下,加深理解。

题目:写出这段程序的打印顺序。并解释一下原理。 async function async1() { console.log('async1 start'); await async2(); console.log('asnyc1 end'); } async function async2() { console.log('async2'); } console.log('script start'); setTimeout(() => { console.log('setTimeOut'); }, 0); async1(); new Promise(function (reslove) { console.log('promise1'); reslove(); }).then(function () { console.log('promise2'); }) console.log('script end'); 解题思路:

做这道题之前我们首先要知道一个概念,就是js代码的执行顺序:

JavaScript 代码在运行时会被分为两种任务类型:宏任务和微任务。 宏任务包括整体代码 script,setTimeout,setInterval,setImmediate 和 I/O 操作等。而微任务则包括 process.nextTick,Promise,async/await 和 MutationObserver 等。 JavaScript 的执行顺序遵循一个事件循环机制,在每一次循环中,会执行一个宏任务,并执行它产生的所有微任务,然后进入下一次循环。一般来说,一个宏任务执行过程中,会产生若干个微任务,它们会被加入任务队列,等待当前宏任务执行完毕后,执行微任务队列中的所有任务。 具体地,JavaScript 代码的执行顺序如下:

执行全局代码,初始化全局环境。 从宏任务(macrotask)队列中取出一个最先进入队列的任务,执行它。 在执行过程中,产生的微任务(microtask)会被加入到微任务队列中。 等待当前宏任务和所有微任务都执行完毕,进入下一轮事件循环,取出一个最先进入任务队列的宏任务,执行它,如果此时宏任务队列中没有任务,则等待新的宏任务加入队列。 重复上述步骤,直到程序结束。

需要注意的是,JavaScript 代码执行期间,只有一个宏任务在执行,也只有一个微任务队列。因此,如果当前宏任务还没有执行完毕,新的宏任务是不会被执行的,直到当前宏任务执行完毕后,再执行下一个宏任务。同时,当当前宏任务执行完毕后,先处理微任务队列中的所有任务,然后再进入下一个宏任务的执行。

了解了什么是宏任务和微任务,就好理解多了,简单解释一下就是,在js执行过程中,首先执行

宏任务 => 微任务的Event Queue => 宏任务的Event Queue。

理解了执行顺序: js在对 setTimeOut的处理方式

 setTimeOut并不是直接的把你的回掉函数放进上述的异步队列中去,而是在定时器的时间到了之后,把回掉函数放到执行异步队列中去。如果此时这个队列已经有很多任务了,那就排在他们的后面。这也就解释了为什么setTimeOut为什么不能精准的执行的问题了。setTimeOut执行需要满足两个条件:

1. 主进程必须是空闲的状态,如果到时间了,主进程不空闲也不会执行你的回掉函数  2. 这个回掉函数需要等到插入异步队列时前面的异步函数都执行完了,才会执行 

也就是说当定时器的时间到了之后,会将内部函数放入宏任务的Event Queue,并不会立即执行。

promise、async/await

首先,new Promise是同步的任务,会被放到主进程中去立即执行。而.then()函数是异步任务会放到异步队列中去,那什么时候放到异步队列中去呢?当你的promise状态结束的时候,就会立即放进异步队列中去了。

带async关键字的函数会返回一个promise对象,如果里面没有await,执行起来等同于普通函数;如果没有await,async函数并没有很厉害是不是。 await 关键字要在 async 关键字函数的内部,await 写在外面会报错;await如同他的语意,就是在等待,等待右侧的表达式完成。此时的await会让出线程,阻塞async内后续的代码,先去执行async外的代码。等外面的同步代码执行完毕,才会执行里面的后续代码。就算await的不是promise对象,是一个同步函数,也会等这样操作。

根据上述我们将题目进行一下解析

执行顺序:宏任务 => 微任务的Event Queue => 宏任务的Event Queue。

 根据图片显示我们来整理一下流程:

执行全局代码,输出 “script start”调用 async1() 函数,输出 “async1 start”调用 async2() 函数,输出 “async2”await async2() 的执行结果会返回一个 resolved Promise,async1() 函数暂停执行,跳转到下面的代码等待 Promise 执行完成。执行一个 Promise,输出 “promise1”,并立即执行 Promise 的回调函数(reslove),输出 “promise2”setTimeout() 函数被调用,因为时间为0,会被加入宏任务(macroTask)队列。执行下一个宏任务,返回 async1() 函数的继续执行,输出 “asnyc1 end”执行宏任务队列中的任务,输出 “setTimeOut”

因为在异步执行时,不会中断代码之间的同步的关系。所以 “Promise1” 的执行不会影响 async1() 函数的异步执行,而 Promise 对象 Promise2 是微任务,在当前同步任务结束后被执行。最后,定时器的回调也是宏任务,所以会在 “Promise2” 执行后输出。

参考:(18条消息) 关于async/await、promise和setTimeout执行顺序_async promise settimeout执行顺序_yun_hou的博客-CSDN博客



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3