问题描述:以下这段代码的执行结果
    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 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。
  • JS调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。
  •  Javascript单线程任务被分为同步任务异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

JavaScript中,任务被分为两种,一种宏任务(MacroTask),一种叫微任务(MicroTask)。

MacroTask(宏任务)

  • script全部代码、setTimeoutsetInterval

MicroTask(微任务)

  • Promise、await
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务队列是否为空,如果为空的话,就执行宏任务,否则就一次性执行完所有微任务。
每次单个宏任务执行完毕后,检查微任务队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务后,设置微任务队列为null,然后再执行宏任务,如此循环。
 
 
运行之前我们需要知道以下几点
  • setTimeout属于宏任务
  • Promise本身是同步的立即执行函数,Promise.then属于微任务
  • async方法执行时,遇到await会立即执行表达式,表达式之后的代码放到微任务执行

下面我们就来运行代码

第一次执行:执行同步代码

Tasks(宏任务):run script、 setTimeout callback
Microtasks(微任务):await、Promise then
JS stack(执行栈): script
Log: script start、async1 start、async2、promise1、script end

第二次执行:执行宏任务后,检测到微任务队列中不为空、一次性执行完所有微任务

Tasks(宏任务):run script、 setTimeout callback
Microtasks(微任务):null
JS stack(执行栈): await、Promise then
Log: script start、async1 start、async2、promise1、script end、promise2、async1 end

第三次执行:当微任务队列中为空时,执行宏任务,执行setTimeout callback,打印日志。

Tasks(宏任务):null

Microtasks(微任务):null

JS stack(执行栈):setTimeout callback
Log: script start、async1 start、async2、promise1、script end、promise2、async1 end、setTimeout

关于73以下版本和73版本的区别

  • 在老版本版本以下,先执行promise2,再执行async1 end
  • 在73及以上版本,先执行async1 end再执行promise2
  • 具体资料可以查询  https://v8.js.cn/blog/fast-async/

 于是我们就得到了这段代码的执行结果(70版本)

(73及以上版本执行结果为)

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
 

setTimeout、Promise、Async/Await 的执行顺序的更多相关文章

  1. 一道题理解setTimeout,Promise,async/await以及宏任务与微任务

    今天看到这样一道面试题: //请写出输出内容 async function async1() { console.log('async1 start'); await async2(); consol ...

  2. JS中的async/await的执行顺序详解

    虽然大家知道async/await,但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解 JavaScript 的 async/await(如果对async/await不熟悉 ...

  3. ES6 class setTimeout promise async/await 测试Demo

    class Person { async getVersion () { return new Promise((resolve, reject) => { setTimeout(functio ...

  4. .net 关于Task.Run 和 Async await的执行顺序

    一直捋不清楚用Task.Run异步的执行关系,网上找的些说明写得也有点复杂,所以自己做实验测一下. 直接上代码 这个是加await private static void TestFun() { Co ...

  5. async await 的执行

    async await的执行 注意:本次代码仅在 Chrome 73 下进行测试. start 不了解 async await 的,先去看阮一峰老师的文章async 函数. 先来看一道头条的面试题,这 ...

  6. 详解promise、async和await的执行顺序

    1.题目和答案 一道题题目:下面这段promise.async和await代码,请问控制台打印的顺序? async function async1(){ console.log('async1 sta ...

  7. 理解 async/await 的执行

    这是一篇简单的短文章,方便理解. 开局先丢官宣:sec-async-function-definitions 这个链接是对 await 的解释,解释了它的执行. await 的执行意味着(官宣巴拉巴拉 ...

  8. node.js async/await 继发执行与并发执行

    async/await 继发执行与并发执行,看如何控制 两个异步函数 foo bar function foo() { return new Promise((resolve, reject) =&g ...

  9. vue使用技巧:Promise + async + await 解决组件间串行编程问题

    业务场景描述 大家都通过互联网投递过简历,比如在智联.58.猎聘等平台.投递心仪的职位前一般都需要前提创建一份简历,简历编辑界面常规的布局最上面是用户的个人基本信息,如姓名.性别.年龄.名族等,接着是 ...

随机推荐

  1. Prometheus 后续杂记

    在后续prometheus的使用中遇到的一些问题我会在此记录 搭建初期几个问题 rule.yml中对每条告警加上主机名? 要在告警通知中加上故障机器主机名不能从prometheus的采集监控项数据中的 ...

  2. 数据库MySQL(课下作业,必做) 20175225

    作业要求: 1.下载附件中的world.sql.zip, 参考http://www.cnblogs.com/rocedu/p/6371315.html#SECDB,导入world.sql,提交导入成功 ...

  3. @清晰掉 spi协议及工作原理分析

    说明.文章摘自:SPI协议及其工作原理浅析 http://bbs.chinaunix.net/thread-1916003-1-1.html 一.概述. SPI, Serial Perripheral ...

  4. c/c++二级指针动态开辟内存

    c版: #include <stdio.h> #include <stdlib.h> #define row 4 #define col 8 int main() { int ...

  5. spring boot官方配置

    #BANNER banner.charset = UTF-8 #横幅文件编码.banner.location = classpath:banner.txt #横幅文件位置.banner.image.l ...

  6. 阶段3 1.Mybatis_11.Mybatis的缓存_3 mybatis一对一实现延迟加载

    不用骨架创建项目 复制一对多的代码src下的代码到我们刚才创建的项目里面 把依赖信息复制过来 这里原来实现的功能是立即加载的功能.sql语句是一次性查询的两个表关联的查询. 调整代码 删除Accoun ...

  7. 阶段3 1.Mybatis_04.自定义Mybatis框架基于注解开发_2 回顾自定义mybatis的流程分析

  8. rename()函数(包含更改索引列列名的方法)

    1 rename()可以更换列名和行名,必须写上columns或index,否则无效 import pandas as pd df = pd.DataFrame({'a':[1,2], 'b':[3, ...

  9. c++ 事件回调 java

    #pragma once #ifdef __cplusplus extern "C" { #endif typedef void(*sig_t)(int); int FirstEl ...

  10. mount挂载相关指令

    最近需要重新挂载一块数据盘,增加挂载设置,遇到一些问题做下记录. step1:df -h 或 lsblk 查看分区挂载和对应挂载的目录 /dev/xxx /data step2:umount /dev ...