好的程序员的web前端分享JS引擎的执行机制。首先,JS是一种单线程语言。JS的EventLoop是JS的执行机制。深刻理解了JS的执行,就相当于深刻理解了JS中的eventloop。1.三个灵魂问题:JS为什么是单线程?为什么需要异步?单线程是如何实现异步的? 技术的出现与现实世界中的应用场景密切相关。同样,我们将结合现实场景来回答这三个问题。(1)为什么JS是单线程的?JS本来就是为了在浏览器中使用而设计的,那么想象一下如果浏览器中的JS是多线程的。 场景描述: 现在有两个进程,process1process2,因为是多进程JS,所以同时操作同一个dom。Process1删除dom,process2编辑dom,同时发出两条相互矛盾的命令。浏览器应该如何执行呢? 这样一想,应该就很容易理解为什么JS要设计成单线程了。(2)为什么JS需要异步? 如果JS中没有异步,只能自上而下执行。如果上一行的解析时间很长,后面的代码就会被阻塞。对于用户来说,阻塞就意味着“卡住”,导致用户体验不佳。 所以,JS中存在异步执行。(3)JS单线程是如何实现异步的? 既然JS是单线程的,只能在一个线程上执行,那么它是如何实现异步的呢? 就是通过事件循环(eventloop),了解eventloop机制,了解JS的执行机制。2.Eventloop(1) JS中的例子1,观察其执行顺序console.log(1)setTimeout(function(){console.log(2)},0)console.log(3) 的运行结果为:132 也就是说setTimeout中的函数不是立即执行,而是延迟一段时间,在满足一定条件后执行。这种类型的代码称为异步代码。 所以,这里我们先知道JS中的一种分类方法,就是把任务分为:同步任务和异步任务。 按照这种分类方式:JS的执行机制是: 先判断JS是同步还是异步,如果是同步则进入主流程,如果是异步则进入eventtable,经过条件后,压入eventqueue 同步任务进入主线程后,会一直执行到主线程空闲,然后去eventqueue中检查是否有可执行的异步任务。如果有,它将被推入主进程。 那么在上面的例子中,你能描述一下它的执行顺序吗?console.log(1)是同步任务,放到主线程里面setTimeout()是异步任务,放到eventtable里面,0秒后执行push到eventqueueconsole.log(3是一个同步任务,放在主线程里面 当controlbar上打印出1和3的时候,主线程就去eventqueue(事件队列)中检查是否有可执行的函数,执行setTimeout中的函数。3.eventloop(2) inJS那么,上面的eventloop就是我对JS执行机制的理解,直到我遇到了下面的代码 Example2:setTimeout(function(){console.log('Thetimer已经启动')});newPromise(function(resolve){console.log('现在执行for循环');for(vari=0;i<10000;i++){i==99&&resolve();}}).then(function(){console.log('Thenfunctionisexecuted')});console.log('Codeexecutionends'); 试试看,上面我们刚学的JS执行机制来分析:setTimeout是一个异步任务,就是pleventtablenewPromise中的aced是同步任务,放在主进程中,直接执行打印console.log中的函数('现在执行for循环').then是异步任务,放在eventtableconsole.log('代码执行结束')。是同步代码,放入主进程直接执行 所以,结果是:立即执行for循环---代码执行结束---定时器启动---是然后功能执行? 亲自执行后,结果不是这样的,而是:立即执行for循环---代码执行完毕---执行then函数---定时器已经启动 所以,是不是异步任务的执行顺序,不是前后顺序,而是其他规定?其实按照异步和同步的划分,是不准确的。 准确的划分方法是:macro-task(宏任务):包括整体代码脚本,setTimeout,setIntervalmicro-task(微任务):Promise,process.nextTickJS引擎执行机制 按照这种分类方式,JS执行机制为: 执行一个宏任务,如果在执行过程中遇到微任务,则将其放入微任务的“事件队列” 当前宏任务执行完毕后,勾选“事件队列”Queue,依次执行所有的microtasks 重复以上2步,结合eventloop(1)eventloop(2),是一个更准确的JS执行机制 试试看刚学的执行机制,来分析例子2: 先执行脚本下的宏任务,遇到setTimeout就放入宏任务的“队列” 遇到newPromise直接执行,打印“现在执行for循环》 遇到then方法就是microtask,p把它放在微任务的“队列”中。 打印“代码执行完成” 本轮宏任务执行完毕,查看本轮微任务,在then方法中找到一个函数,打印“then函数执行完毕” 这里,这个round事件循环就全部完成了。 在下一个循环中,先执行一个宏任务,发现宏任务的“队列”中有setTimeout中的一个函数,执行并打印“定时器已启动” 于是最后的执行顺序就是:立即执行for循环---代码执行结束---执行then函数---定时器启动4、说说setTimeout 这段setTimeout代码是什么意思?我们一般说:3秒后,setTimeout会执行setTimeout(function(){console.log('executed')},3000) 但是这个说法并不严谨,准确的解释是:3秒后秒后,setTimeout中的函数会被推入eventqueue,eventqueue(事件队列)中的任务只会在主线程空闲时执行。
