宏任务 && 微任务 && async && await(图解)

1.宏任务和微任务

宏任务和微任务是等待任务队列中的异步任务的处理机制;(JS执行有同步任务队列和等待任务队列)

浏览器的任务队列:

主任务队列存储的都是同步任务;

等待任务队列存储的都是异步任务;

首先浏览器会把主任务队列中的同步任务挨个全部执行完,然后再去等待任务队列中看哪个任务可以执行了,然后把该执行的任务放到主任务队列中去执行,等这个任务执行完,再去等待任务中看谁可以执行了,再把这个任务放到主任务队列中执行... 如此循环。这种循环叫做事件循环(Event Loop)

异步任务都是谁先到达条件谁先执行,但是谁先到达执行条件也有优先级的问题,这个优先级要看这个任务是宏任务还是微任务;微任务的优先级比宏任务的要高;

所以可以看做是这样的:浏览器线程先执行同步任务,途中遇到异步任务就将其加入到等待任务队列中去,然后继续向下执行,等同步任务全部执行完毕后,再去等待任务队列中去将所有可执行的微任务逐个执行,执行完后在拿取第一个先到达执行条件的宏任务来执行,执行完后再去等待任务队列中清理执行完所有已到达执行条件的微任务,然后再拿取下一个宏任务来执行,如果宏任务执行产生微任务或者微任务执行产生宏任务就一样加入到等待任务队列中,然后还是按照主线程每次到等待队列中先执行完所以的微任务再逐个执行宏任务的顺序来走

 

哪些是微任务:

1. Promise的then的回调函数

2. async 函数await下面的代码;

3. process.nextTick

 

哪些是宏任务:

1. 定时器(setInterval和setTimeout)

 

接下来上一张宏任务微任务的图帮助理解:

那么会有小伙伴疑惑了,那异步操作也不止这几个啊,还有ajax呢?

js执行遇到ajax也会被放进等待任务队列中去,不过不同的是ajax不算是宏任务也不算是微任务,小编做个测试结果就是:ajax达到执行条件就会立即执行,发送请求嘛,网速快就执行的快网速慢就执行的慢,比如下面的代码,

async function f3() {
        p = await 18;
        console.log(1);
}

f3();

console.log(2);

let xhr = new XMLHttpRequest;
xhr.open('GET','实践1/login.json');
xhr.onreadystatechange = () =>{
    if (xhr.readyState === 4 && xhr.status === 200) {
        console.log(3);
    }
};

xhr.send();

setTimeout(() => {
    console.log(4);
});

console.log(5);

这个代码打印出来的结果可能是25143也可能是25134,小编猜测应该是网速快慢决定ajax执行的早晚,但是肯定是比微任务后执行,所以大概是微任务执行完毕会看一下ajax达到执行条件没,达到了就执行ajax,没达到就执行宏任务

2.async和await

async和await 是es6新增的关键字,用于把异步变同步;

async在函数定义时使用,用async定义的函数默认返回一个Promise实例,可以直接.then(async还可以定义对象的方法),如果async定义的函数执行返回的不是一个promise对象,那么就会给返回值包装成一个promise对象(将返回值放进promise实例的resolve方法中当做参数)

await (要和async一起使用,一般是在async声明的函数中使用)

await 会等待,等它右侧的代码执行完;

用法:

1. 如果await右侧是同步的代码,就会让同步代码执行;如果执行的是一个函数,还会把函数的返回值给到await左边的变量

let p;
async function f3() {
    p = await 18;
    console.log(p);
}

f3();
console.log(1);
console.log(p);

//  结果是1,undefined,18

// js执行的时候是从右向左执行的,先执行18然后遇到await会将await左边的连同下面的都放进微任务中去,所以外面的p打印会是undefined,然后同步代码执行完再执行微任务的时候将其执行,给p赋值,打印p

2. 如果await右侧是一个Promise实例,或者一个方法返回了Promise实例,await会等着Promise的实例resolve,并且在实例resolve之前,await后面的代码不执行;并且还会拿到Promise在resolve时传入的值,并且赋值给等号左侧变量;

async function f(){
    return 10;
}

async function f3() {
    let p = await f();
    console.log(p);
}

f3();
console.log(1);

// 打印1,10,上面说了async定义的函数后面如果返回的不是一个promise对象而是一个普通值就会默认包装成一个promise对象,并将其返回值赋值给await左边的变量,如果我们不使用async而是写一个promise对象,如下:

function f(){
    return new Promise(((resolve, reject) => {
        resolve(10);
    }))
}

async function f3() {
    let p = await f();
    console.log(p);
}

f3();
console.log(1);

// 会发现打印的依旧是1,10

3. await会把await下面的代码变成微任务;上面代码就能看出来,先打印1再打印10,就是因为await将下面的代码当做一个微任务整体放进了等待任务队列中

相信很多小伙伴都觉得async和await的功能和promise没什么区别,其实呢,async和await就是promise的语法糖,封装了promise的then链式调用的繁琐以及处理回调的杂乱,让我们更简单更方便的使用promise来管理我们的异步代码

想一想如果我们有a,b,c三个异步操作,要求b依赖于a的返回值,c依赖于b的返回值

使用promise 链式调用

function a() {
    return new Promise(((resolve, reject) => {
        setTimeout(()=>{
            resolve(1);
        },1000)
    }))
}
function b(result) {
    return new Promise(((resolve, reject) => {
        setTimeout(()=>{
            console.log(result);
            resolve(2);
        },2000)
    }))
}
function c(result) {
    return new Promise(((resolve, reject) => {
        setTimeout(()=>{
            console.log(result);
            resolve(3);
        },3000)
    }))
}
let aP=a();
aP.then(b).then(c);

使用async和await

function a() {
    return new Promise(((resolve, reject) => {
        setTimeout(()=>{
            resolve(1);
        },1000)
    }))
}
function b(result) {
    return new Promise(((resolve, reject) => {
        setTimeout(()=>{
            console.log(result);
            resolve(2);
        },2000)
    }))
}
function c(result) {
    return new Promise(((resolve, reject) => {
        setTimeout(()=>{
            console.log(result);
            resolve(3);
        },3000)
    }))
}



async function f() {
    let aP = await a();
    let bP = await b(aP);
    let cP = await c(bP);
}
f();

使用async/await更符合同步执行的思想,看个人喜好使用吧

 

下面是一道很经典的面试题:

   async function async1() {
            console.log( 'async1 start' )
            await async2()
            console.log( 'async1 end' )
        }
        async function async2() {
            console.log( 'async2' )
        }
        console.log( 'script start' )
        setTimeout( function () {
            console.log( 'setTimeout' )
        }, 0 )
        async1();
        new Promise( function ( resolve ) {
            console.log( 'promise1' )
            resolve();
        } ).then( function () {
            console.log( 'promise2' )
        } )
        console.log( 'script end' )

 

其实还是不难的,按照上面图的流程往里面套就行, 如果倒数第二个和第三个结果与我的相反,那说明你的浏览器该更新了

 

 

  • 14
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值