了解javascript事件循环原理?《前端每日一题v22.11.16》理解javascript的第一步就是理解事件循环机制。但是真正理解javascript的事件循环机制并不容易,因为它是javascript引擎最基础的部分。它允许单线程javascript以非阻塞的方式执行事件循环机制EventLoop。要真正理解这一点,我们可能需要知道javascript引擎的相关内容,比如调用栈、宏任务、微任务、任务队列等。下面我们一起来看看这些概念调用栈调用栈是一个数据跟踪javascript代码执行的结构。它是一个栈,所以遵循先进后出的数据结构。每个执行的函数都表示为调用堆栈中的一个帧,并放在最前面。函数的顶部例如,这是最常见的一段javascript代码)下面详细描述一下上面代码的执行流程。调用堆栈最初是空的,忽略所有前面的函数,直到调用foo。列表中加入了console.log函数,这个函数执行完会立即出栈,所以栈列表还在foo代码执行到bar时,函数被调用,bar函数被压入调用栈,调用栈列表为bar-foo,执行bar,直到调用栈中所有代码执行完毕,调用栈列表不变,返回继续执行foo函数中bar之后的代码。删除调用堆栈列表中的bar函数。调用堆栈列表是foofoo.h中的bar函数。没有后续可执行代码来删除调用堆栈。对于列表中的foo,此时调用栈列表为空。一开始,我们会将函数压入空的调用栈。函数代码执行完后,调用栈会移除这个函数,最后会得到一个空的调用栈,如果在执行过程中,以上任务和任务队列的情况主要针对javascript单线程执行方式,但是这种方式是不可取的,比如我们遇到定时器,或者请求数据等执行时间比较长在代码的情况下,后续的逻辑要等到这些代码执行完毕,才能进行下一步。因此,就有了任务队列的概念。任务分为同步任务和异步任务。不同的是,同步任务执行后可以立即得到结果,而异步任务需要等待。需要一段时间才能得到结果。同步任务执行遵循调用堆栈执行逻辑。执行完成后,从调用栈中移除。异步任务执行也会进入调用栈。不同的是它会把它的回调函数或者回调任务放到一个任务队列中。任务队列遵循先进先出的原则,放入任务队列的函数不会立即执行,需要等待调用栈中的同步任务执行完成,当调用栈清空,即所有同步任务完成后,解释器开始读取任务队列执行,将完成的异步任务放入调用栈执行,见代码console.log('foo')setTimeout(()=>{console.log('bar')},1000)console.log('loo')console.log('foo')被压入调用栈,执行完毕,压出调用栈。setTimeout被推入调用堆栈。浏览器的定时线程会等待时间结束,将setTimeout箭头函数中的回调函数放入任务队列。setTimeout推出调用栈console.log('loo')被推入调用栈,执行并释放。此时所有的同步任务都执行完毕,调用栈为空。1秒后,浏览器的计时线程将匿名函数放入任务队列。调用栈为空,执行任务队列。匿名函数内容console.log('bar')执行匿名函数并启动调用栈调用栈为空宏任务和微任务上面说的任务队列其实分为宏任务和微任务,两者都是异步任务,它们的区别在于它们的执行顺序为什么要区分宏任务和微任务?最重要的一点是,如果任务队列中的某个任务耗时1小时,则后续任务需要等待1小时。这显然是不合理的,所以宏任务和微任务最重要的目的之一就是区分任务的优先级。微任务的优先级高于宏任务。宏任务的整体代码属于宏任务。()=>{console.log('bar')},0)newPromise((res)=>{res(1)}).then((d)=>{console.log(d)})命令结合上面foo、1、bar事件循环的内容,基本上就是整个事件循环的机制了。首先,从调用栈开始,将同步任务压入调用栈,开始执行异步任务,将结果压入回调。任务队列,注意区分宏任务和微任务。调用栈清空后,微任务队列按照先入先出的执行顺序开始执行。微任务队列清空后,一个循环结束,进入宏任务队列,直到宏任务队列清空。异步函数async1(){console.log('async1start');等待async2();console.log('async1end');}asyncfunctionasync2(){console.log('async2');}console.log('scriptstart');setTimeout(function(){console.log('setTimeout');},0)async1();newPromise(function(resolve){console.log('promise1');resolve();console.log('promise2')}).then(function(){console.log('promise3');});console.log('脚本结束');按理说,做完这道题,你就可以当老师了,以后再遇到这样的执行序列也不怕了
