我们就以一道面试题开始说起

async function a1 () {
    console.log('a1 start'); //2
    await a2();
    console.log('a1 end');//9
}
async function a2 () {
    console.log('a2');//3
}
 
console.log('script start'); //1
 
setTimeout(() => {
    console.log('setTimeout');//10
}, 0)
 
Promise.resolve().then(() => {
    console.log('promise1');//6
})
 
a1()
 
let promise2 = new Promise((resolve) => {
    resolve('promise2.then');
    console.log('promise2');//4
})
 
promise2.then((res) => {
    console.log(res);//7
    Promise.resolve().then(() => {
        console.log('promise3');//8
    })
})
console.log('script end');//5
//答案:
1、script start
2、a1 start
3、a2
4、promise2
5、script end
6、promise1
7、 promise2.then
8、promise3
9、a1 end
10、setTimeout

不出所料地同学可以走了,对您来说,后续内容通篇废话。

看到以上输出结果感到不可思议的同学,继续往下看。

为什么会出现这种执行顺序,这就要从js的单线程开始说起了,js将所有任务都在一个线程上完成,一旦遇到大量或耗时的任务,就会阻塞,网页现"假死"状态,无法响应用户的行为。于是js引入了Event Loop,来解决单线程运行带来的一些问题。

Wikipedia这样定义Event Loop

事件循环是一种等待或分派程序中事件或消息的编程结构或设计模式。(the event loop is a programming construct or design pattern that waits for and dispatches events or messages in a program.)

简单说,就是在程序中设置两个线程:一个负责程序本身的运行,称为"主线程";另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为"消息线程")。每当遇到I/O的时候,主线程就让Event Loop线程去通知相应的I/O程序,然后接着往后运行,所以不存在等待时间。等到I/O程序完成操作,Event Loop线程再把结果返回主线程。主线程就调用事先设定的回调函数,完成整个任务。

我们来简单的看下js的执行顺序

js 执行顺序

那么看完上图,问题是不是又来了,究竟啥样的算是异步啊。

js异步任务有两种:宏任务和微任务。

宏任务:整体script代码,setTimeout,setInterval

微任务:promise.then,process.nextTick

注意:promise的第一层回调可以看成是同步的,会即时输出

new Promise((resolve) => {
    console.log('promise2'); //可以看成是同步的,会比222222先输出
    resolve();
}).then(()=>{
    console.log(1111); //这里是异步的
})
console.log(222222);

在异步队列里,我们先记住两点:

  1. 微任务先于宏仁务执行
  2. 微任务队列空了,才去执行下一个宏任务

async

async不属于微任务也不属于宏任务,提到它,是因为上面的面试题里面有,我们就来看下吧

async function a() {
    console.log('async');
}
a();
console.log(111);
//输出:async,111

从上图的输出结果,我们看出async函数里面是一个同步的执行,也就是说async本身不是异步的,那么他是如何进行异步操作的呢?下面我们有请await出场

async function a() {
 // await从使用上来说必须等待一个promise
    var c=await new Promise(function(resolve){
        resolve(3333);
    });
    console.log(c);
}
a();
console.log(111);
//输出:111,3333
async function a() {
 // await从使用上来说必须等待一个promise
    var c=await new Promise(function(resolve){
        resolve(3333);
    });
    console.log(555);
    console.log(c);
}
a();
console.log(111);
//输出:111,555,3333

此篇终,看完这个再考虑下经典闭包问题,是不是就更清楚了呢

for(var i=0;i<3,i++){
    setTimeout(function(){
        console.log(i);
    },0);
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐