一文搞懂javascript事件循环原理?「前端每日一题v22.11.16」
了解javascript的第一步,就是要了解事件循环机制。但是要真正的了解javascript的事件循环机制并不容易,因为它是javascript引擎最基础的部分。它可以让单线程的javascript以非阻塞方式执行
事件循环机制Event Loop,要真正了解这些,我们可能需要知道javascript引擎相关内容,比如调用栈,宏任务,微任务,任务队列等相关,一起看一下这些概念
调用栈是一种跟踪javascript代码执行的数据结构,它是一个栈,因此遵循先进后出的数据结构,执行的每个函数都表示为调用栈中的一个帧,并放在前一个函数的顶部
举个例子,这是最常见的一段javascript代码
function foo(){
console.log('foo')
bar()
}
function bar(){
console.log('bar')
}
foo()
我们详细的讲述一下上述代码的执行流程
一开始我们会往空的调用栈中推入函数,执行完函数代码之后,调用栈又会移除这个函数,最终又会得到一个空的调用栈,如果在执行过程中,
上面的案例主要是针对javascript单线程的执行方式,但是这种方式是不可取的,比如如果我们碰到了定时器,或者请求数据等执行时间比较长的代码的话,后面的逻辑就得等这些代码执行完成才能进行下一步
所以就有了任务队列的概念
任务分为同步任务和异步任务,区别就是同步任务执行后立刻就能取到结果,异步任务需要等一会儿才能取到结果
同步任务执行按照调用栈执行逻辑,执行完成移出调用栈,异步任务执行也会进入调用栈,不同的是它会将其回调函数或者回调任务放入一个任务队列,任务队列遵循先进先出的原则,放入任务队列的函数不会立刻执行,需要等待调用栈中同步的任务执行完成
当调用栈清空之后,也就是所有同步任务结束之后,解释器开始读取任务队列执行,将「已经完成」的异步任务放入调用栈执行
看代码
console.log('foo')
setTimeout(() => {
console.log('bar')
}, 1000)
console.log('loo')
前面说到的任务队列,其实还分为宏任务和微任务,这两种都属于异步任务,它们的区别就在于它们的执行顺序。
为什么会区分宏任务和微任务,最主要的一点就是如果任务队列中某一个任务需要1个小时,后续的任务都需要等待一个小时,这显然是不合理的,所以宏任务和微任务最主要的一个目的就是区分任务的优先级,微任务优先级高于宏任务
「宏任务」
「微任务」
console.log('foo')
setTimeout(() => {
console.log('bar')
}, 0)
new Promise((res) => {res(1)}).then((d) => {console.log(d)})
顺序为foo、1、bar
上面的内容结合起来,基本上就是整个事件循环的机制了
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();
console.log('promise2')
}).then(function () {
console.log('promise3');
});
console.log('script end');
按照以上逻辑,做完这个题就可以出师了,以后碰到所有的这种执行顺序的都不怕了