JS【详解】在浏览器中 JS 代码的执行顺序(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)

js 的同步任务和异步任务

js代码可以分为两种任务:

  • 同步任务(synchronous)—— 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

  • 异步任务(asynchronous)—— 不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

    异步任务又分为宏任务与微任务:

    • 宏任务(macrotask )
    事件/函数浏览器环境Node.js环境
    I/O
    setTimeout
    setInterval
    setImmediate
    requestAnimationFrame
    • 微任务(microtask )
    事件/函数浏览器环境Node.js环境
    process.nextTick
    MutationObserver
    Promise.then catch finally

js在浏览器中的运行机制

从上到下依次解释执行所有代码

  • 遇到同步任务时,在主线程立刻执行该任务。

    此时主线程上有一个执行栈(execution context stack),所有同步代码会按顺序执行。

  • 遇到异步任务时,异步任务会进入到Event Table,当异步任务有结果后,将相对应的回调函数进行注册,放入事件队列(Event Queue);(异步的宏任务有结果后,会放入宏任务事件队列;异步的微任务有结果后,会放入微任务事件队列;)

(1)主线程从上到下依次执行所有同步任务
(2)主线程读取微任务事件队列,若存在微任务,则依次执行所有微任务

  • 微任务中同步任务会依次立刻执行
  • 微任务中微任务会依次添加到微任务事件队列末尾,待下一次读取微任务事件队列时执行
  • 微任务中宏任务会依次添加到宏任务事件队列末尾,待下一次读取宏任务事件队列时执行

微任务执行完毕后,开始DOM 渲染

DOM 渲染结束后,开始事件轮询 Event Loop,执行宏任务

(3)主线程读取宏任务事件队列,若存在宏任务,则依次执行所有宏任务

  • 宏任务中同步任务会依次立刻执行
  • 宏任务中微任务会依次添加到微任务事件队列末尾,待下一次读取微任务事件队列时执行
  • 宏任务中宏任务会依次添加到宏任务事件队列末尾,待下一次读取宏任务事件队列时执行

(4)依次重复第2步和第3步,直到清空微任务事件队列和宏任务事件队列

Event Loop(事件轮询):主线程循环不断从"任务事件队列"中读取事件的运行机制称为Event Loop,这个过程是循环不断的,所以整个的这种运行机制

Event Loop 并不是在 ECMAScript 标准中定义的,而是在 HTML 标准中定义的

测试 js 在浏览器中运行机制的代码

console.log('0号同步任务1');
new Promise(function (resolve) {
    console.log('0号同步任务2');
    resolve();
}).then(function () {
    // 1号微任务
    setTimeout(function () {
        console.log('1号微任务中的宏任务1');
    })
    console.log('1号微任务中的同步任务1')
    new Promise(function (resolve) {
        console.log('1号微任务中的同步任务2');
        resolve();
    }).then(function () {
        // 1.1号微任务
        console.log('1.1号微任务中的同步任务1')
        setTimeout(function () {
            console.log('1.1号微任务中的宏任务1');
        })
        console.log('1.1号微任务中的同步任务2')
        setTimeout(function () {
            console.log('1.1号微任务中的宏任务2');
        })
    })
    console.log('1号微任务中的同步任务3')
    setTimeout(function () {
        console.log('1号微任务中的宏任务2');
    })
})
setTimeout(function () {
    console.log('0号宏任务中的同步任务1');
    new Promise(function (resolve) {
        console.log('0号宏任务中的同步任务2');
        resolve();
    }).then(function () {
        // 0号宏任务中的1号微任务
        setTimeout(function () {
            console.log('0号宏任务中的1号微任务中的宏任务1');
        })
        console.log('0号宏任务中的1号微任务中的同步任务1')
        new Promise(function (resolve) {
            console.log('0号宏任务中的1号微任务中的同步任务2');
            resolve();
        }).then(function () {
            //  0号宏任务中的1.1号微任务
            console.log('0号宏任务中的1.1号微任务中的同步任务1')
            setTimeout(function () {
                console.log('0号宏任务中的1.1号微任务中的宏任务1');
            })
        })
        console.log('0号宏任务中的1号微任务中的同步任务3')
    })
})
new Promise(function (resolve) {
    console.log('0号同步任务3');
    resolve();
}).then(function () {
    // 2号微任务
    setTimeout(function () {
        console.log('2号微任务中的宏任务1');
    })
    console.log('2号微任务中的同步任务1')
    new Promise(function (resolve) {
        console.log('2号微任务中的同步任务2');
        resolve();
    }).then(function () {
        // 2.1号微任务
        console.log('2.1号微任务中的同步任务1')
        setTimeout(function () {
            console.log('2.1号微任务中的宏任务1');
        })
    })
    console.log('2号微任务中的同步任务3')
})
console.log('0号同步任务4');

运行结果

0号同步任务1
0号同步任务2
0号同步任务3
0号同步任务4
1号微任务中的同步任务1
1号微任务中的同步任务2
1号微任务中的同步任务3
2号微任务中的同步任务1
2号微任务中的同步任务2
2号微任务中的同步任务3
1.1号微任务中的同步任务1
1.1号微任务中的同步任务2
2.1号微任务中的同步任务1
0号宏任务中的同步任务1
0号宏任务中的同步任务2
0号宏任务中的1号微任务中的同步任务1
0号宏任务中的1号微任务中的同步任务2
0号宏任务中的1号微任务中的同步任务3
0号宏任务中的1.1号微任务中的同步任务1
1号微任务中的宏任务1
1号微任务中的宏任务2
2号微任务中的宏任务1
1.1号微任务中的宏任务1
1.1号微任务中的宏任务2
2.1号微任务中的宏任务1
0号宏任务中的1号微任务中的宏任务1
0号宏任务中的1.1号微任务中的宏任务1
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朝阳39

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值