JavaScript基础:事件循环

128 阅读2分钟

Event Loop

事件循环(Event Loop)指的是计算机系统的一种运行机制,JavaScript采用这种机制来解决单线程运行带来的一些问题。

JavaScript为什么设计成单线程?

image.png

事件循环机制

image.png

主线程从任务队列中读取任务,执行任务,整个过程是循环往复的,整个运行机制又被称为Event Loop

// 两分钟视频理解Event Loop
www.bilibili.com/video/BV1kf…

宏任务和微任务

image.png

事件循环中的执行步骤

image.png

思考题

进程和线程的关系

进程可以包含多个线程。

比如打开一个页面,这个页面占用了计算机的一个进程,页面加载时,浏览器会分配多个线程去计算DOM树、执行JS脚本、加载资源文件等。

宏任务和页面渲染的顺序关系

浏览器为了能够使得JS内部宏任务与DOM任务能够有序的执行,会在一个宏任务执行结束后,在下一个宏任务执行开始前,对页面进行重新渲染。流程如下:

(macro)task->渲染->(macro)task->...

为什么要引入微任务,只有宏任务可以吗?

微任务的引入是为了解决异步回调的问题。
假设只有宏任务,那么每一个宏任务执行完后回调函数也放入宏任务队列,这样会造成队列多长,回调的时间变长,这样会造成页面的卡顿,所以引入了微任务。

await后面的代码会进入到promise队列中的微任务

async/await 只是操作 promise 的语法糖,最后的本质还是promise。

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
// 上面的代码等价于 ==>
async function async1() {
    console.log('async1 start');
    Promise.resolve(async2()).then(() => {
        console.log('async1 end')
    })
}

例题

例题1

console.log("start");
setTimeout(() => {
    console.log("children2")
    Promise.resolve().then(() =>{
        console.log("children3")
    })
}, 0)

new Promise(function(resolve, reject){
    console.log("children4")
    setTimeout(function(){
        console.log("children5")
        resolve("children6")
    }, 0)
}).then(res =>{         // flag
    console.log("children7")
    setTimeout(() =>{
        console.log(res)
    }, 0)
})
// start children4 children2 children3  children5  children7 children6

上面的.then() (注释的flag处) 不是第一轮宏任务循环的微任务。因为resolve都没有执行,promise的状态都还没有从pending改变,就不是第一轮的微任务。

例题2

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((resolve) => {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')
//输出
//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//setTimeout

例题3

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

例题4

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