<返回更多

JavaScript的宏任务和微任务

2020-08-27    
加入收藏

JAVAScript是单线程的语言,也就是说同一时间只能进行一个任务,毕竟JavaScript可以操作dom,进行ui交互,删除dom和修改dom同时进行,那么应该听哪一个?。

正是因为这样,决定了它是单线程的,但是又说单线程只能在同一个时间内执行一个任务,这样岂不是会造成阻塞?前一个任务执行很久,后面都卡死了,所以就需要JavaScript的事件循环机制来进行分配,这样就会被分为

宏任务:当前调用栈执行的代码称为宏任务

宏任务有哪些?

微任务:当前宏任务执行完,在下一个宏任务开始之前需要执行的在队列(先进先出)里的任务,可理解为回调事件

微任务有哪些?

运行机制,面试中经常会遇到这样的题目(让说出它的执行顺序):

console.log('1');

setTimeout(function() {

    console.log('2');

}, 0);

Promise.resolve().then(function() {    

console.log('3');

}).then(function() {    

console.log('4');});

console.log('5');

执行结果:1 5 3 4 2

先了解一下运行机制:

1. 在执行栈中执行一个宏任务(程序刚开始执行时,会把整个代码当成第一个宏任务)。

2. 执行的过程中遇到微任务,先将微任务添加到微任务队列中(它是属于本次执行的宏任务中分出来微任务),遇到宏任务,放到下一个执行栈中。

3. 当前宏任务执行完毕,立即执行任务队列(先进先出的原则)中的微任务

4. 当前微任务队列中的任务执行完毕

5. 接着开始执行执行栈中的下一个宏任务,

6. 依次循环这个规律

解析上面的代码:

1. 整体代码被当成第一个宏任务,代码从上到下执行

2. 遇到console.log('1');是同步任务,直接执行,输出1

3. 遇到setTimeout,是宏任务,放到执行栈中

4. 再往下执行,遇到promise,promise的执行器里是立即执行的,这里没有执行器,而是有then,then是微任务,先放到本次宏任务的微任务队列中,then后面返回的也是一个promise,第二个then也是一个微任务,放到微任务队列中。

5.接着遇到同步代码console.log('5');直接输出5,这时候,第一轮宏任务执行完毕

6.需要去执行本轮它产生的微任务,先进先出的原则,输出3 4

7.这时候循环的第一周期就结束了

8.再去执行栈中的第二个宏任务,输出 2


来个难的练习一下:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

结果:1 7 6 8 2 4 3 5 9 11 10 12

process.nextTick 需要放在node环境下才能执行:

JavaScript的宏任务和微任务

 


加上async和await

async function async1() {
    console.log('1');
    let a = await async2();
    console.log(a);
    console.log('2');
}

async function async2() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve('data');
        }, 0);
    });
}

console.log('3');

setTimeout(function () {
    console.log('4');
}, 0);

async1();

new Promise(function (resolve) {
    console.log('5');
    resolve();
}).then(function () {
    console.log('6');
});

console.log('7');

// 3 1 5 7 6 4 data 2

提示:

  1. await是一个让出线程的标志
  2. 正常情况下, await 命令后面是一个 Promise 对象。如果不是,会被转成一个立即 resolve 的 Promise 对象
  3. 当函数执行的时候, 一旦遇到 await 就会先返回,跳出函数体执行外部的代码,等到异步操作完成,再接着执行函数体内后面的代码。
声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>