被说一知半解,await不懂你别乱用

1.前言

这篇文章我是不想写的,因为之前已经写过了(异步回调Async Await与Promise区别),此时此刻的心情是非常的不满,为什么呢? 因为前几天项目中把多层promise链式回调用了用 es6的await改写了,当我们前端XXX看到之后很疑惑,就问,为什么这么写?你知道await是什么吗?我说知道,await后面是返回的一个promise的resolve/reject的结果,这样的目的可以避免很多promise链式嵌套回调,而且await 的promise不执行完,下面代码也不会执行!代码看上去也很同步,他很不屑的看了我一眼,别一知半解的在那乱用(我们公司的领导说话口气都这样),别以为我不懂,这个await就是等待的意思!它就是个同步代码,会阻塞主线程,以前写什么XXX的时候,用这个会导致浏览器卡死不动,在后端服务器会直接DOWN掉,不知道不要乱用?,其实我很想解释,但是我觉得当时的情况,我多说无益,其实我这样写也是为了让代码更加清晰,以后维护起来也方便!无奈之举!只能改回promise的链式嵌套写法,这篇文章我会分析下我对await(一知半解)的理解!

2.await是否阻塞主线程?

先说下 await的正确使用,await必须是在这个async声明的函数内部使用,async是什么意思?异步的意思,看到这个东西也知道这个是个异步的函数,会阻塞主线程?,javascript虽然是单线程,先执行同步代码,碰到异步函数的会扔进异步队列里面,等主线程空闲了再把异步队列再把异步函数放进主线程执行,下面我来证实下我的观点

let test = async () =>{
    return await new Promise((resolve, reject)=>{
        setTimeout(() =>{
            resolve("第一个请求")
            console.log("第一个请求")
        }, 5000)
    });
}

test();

for (let i = 0; i < 10; i++) {
    setTimeout((i) =>{
        console.log("我执行了" + i + "次")
    }, 1000 * i, i);
}

按正常执行顺序,主线程执行到test函数时,如果是同步的,那么下面的for循坏更本不会执行!我们来看执行结果

在这里插入图片描述
结论:所以可以跟明确的得出结论,它不会阻塞主线程!


3.await是否同步?

首先要明白await的用法,当await后面的不是promise,它会不会阻塞?看下面代码!

function forLoop() {
   for (let i = 0; i < 10; i++) {
       setTimeout((i) =>{
           console.log("我执行了" + i + "次")
       }, 1000 * i, i);
   }
}

let test = async () => {
    await forLoop();
   console.log("我执行不执行");
}
test();

await 后面不是个promise,而是个for循环,里面有个setTimout,这个又涉及到宏任务了(先不管,暂且他看成异步),那么await 后面接到一个异步setTimout的函数,那么我下面的 console.log还会执行吗?还是会卡在这里,等setTimout函数执行完再执行呢?让结果来告诉我们!
在这里插入图片描述
结论:如果await后面接的不是promise,那么它是按正常顺序执行的,先同步后异步,需要注意的await后面属于微任务,所以,这种情况也不会阻塞

如果await 后面接的是promise,那么await后面的代码就相当在promise.then()里面执行,promise.then里面是个微任务如果不懂可以点击javascript执行机制所以我们来看下例子回忆下

setTimeout(() => {
    console.log("setTimeout宏任务")
}, 0);

let test = async () =>{
    console.log("promise 同步代码1")
    let onePromise = await new Promise((resolve, reject) => {
        resolve("success")
    });
    console.log("promise微任务执行2");
}

test();

new Promise((resolve, reject) => {
    console.log("promise 同步代码")
    resolve("success");
}).then((data) => {
    console.log("promise微任务执行1")
})
console.log("end");

简单分析下,一开始setTimeout宏任务扔进任务队列,接着执行console.log("promise 同步代码1"), console.log("promise微任务执行2")是在promise.then中执行的所以是个微任务扔进任务队列,接着执行 console.log("promise 同步代码"), 又一个 console.log("promise微任务执行1") 微任务扔进任务队列,接着执行console.log("end"),看下任务队列有没有微任务,按顺序执行 console.log("promise微任务执行2"),再执行 console.log("promise微任务执行1"),最后执行下一轮事件循环,执行 console.log("setTimeout宏任务"),后面没有微任务了,结束事件循环!
在这里插入图片描述

let test = async () => {
    let onePromise = await new Promise((resolve, reject) => {
        resolve("success")
    });
   let result = "promise微任务执行2" ;
   console.log(result); 
}

test();

//等价于

let test = async () => {
    let onePromise = await new Promise((resolve, reject) => {
        resolve("success")
    });
}
test().then((data)=>{
  let result = "promise微任务执行2" ;
  console.log(result);
});

await 后面的执行都相当于放到了Promise.resolve(),很显然是成功的回调函数!那么多个await呢?我们来模拟下

let asyncFn1 = async () => {
    await new Promise((resolve, reject) => {
        resolve("success1")
        console.log("success1");
    });
    await new Promise((resolve, reject) => {
        resolve("success2")
        console.log("success2");
    });
    await new Promise((resolve, reject) => {
        resolve("success3");
        console.log("success3");
    });
}
asyncFn1();


//等价于


let asyncFn1 = async () => {
   await new Promise((resolve, reject) => {
       resolve("success1")
       console.log("success1");
   });
}
asyncFn1().then((data) => {
   let asyncFn2 = async () => {
       await new Promise((resolve, reject) => {
           resolve("success2")
           console.log("success2");
       });
   }
   asyncFn2().then(() => {
       let asyncFn3 = async () => {
           await new Promise((resolve, reject) => {
               resolve("success3")
               console.log("success3");
           });
       }
       asyncFn3().then(() => {

       })
   });
});

在这里插入图片描述

看上面这种代码转变,那么你应该知道这个和promise链式调用有没有什么区别?为什么es6要出async,await,就是为了解决这种多个promise链式调用嵌套的,它是promise的升级版!只是在promise原有的基础上升级了,让我们调用的时候代码看起来更清晰!

let asyncFn1 = async () => {
    let onePromise = await new Promise((resolve, reject) => {
        setTimeout(function () {
            resolve("第一个请求");
            console.log("第一个请求");
        }, 5000)
    });
    console.log("我要先执行");
}

asyncFn1();

像上面这种写法是有问题,要等onePromise 执行完成之后才会执行下面的,但是你别忘记了await的初衷,你肯定不会愚蠢到把先要执行的东西放到一个promise的回调里面吧

结论:如果await后面接的是promise,那么它是严格按照代码顺序执行的,此时是同步的,因为后面的代码都是promise的成功回调


4.总结

await不会阻塞主线程,不会导致浏览器假死,卡死,anync是个异步函数,会被放进异步队列,等主线程空闲了才会放进主线程,await后面的代码如果是promise,那么是同步的,如果不是promise,那么执行规则是先同步后异步,但是你要了解await,它是为了解决promise链式调用嵌套而存在的,就算是promise链式嵌套,它的执行也是同步!所以要在合适的使用场景正确使用!(你可能写个循环都会出现死循环导致浏览器崩溃)

  • 68
    点赞
  • 122
    收藏
    觉得还不错? 一键收藏
  • 48
    评论
评论 48
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值