好的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中没有异步,只能自上而下执行。如果上一行的解析时间很长,后面的代码就会被执行block。对于用户来说,阻塞就意味着“卡住”,导致用户体验不佳。 所以,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中检查是否有可执行的异步任务。如果有,则推入主进程 ,循环执行以上三步。这是事件循环。 那么在上面的例子中,你能描述一下它的执行顺序吗? console.log(1)为同步任务,放入主线程 setTimeout()为异步任务,放入eventtable,0秒后推入eventqueue console.log(3是同步任务,放在主线程里面 controlbar中打印1和3的时候,主线程去eventqueue(事件队列)检查是否有可执行函数,执行setTimeout中的函数 3、JS中的eventloop(2) 所以,上面的eventloop是我对JS执行机制的理解,直到遇到下面这段代码。 示例2: setTimeout(function(){console.log('定时器已启动')}); newPromise(function(resolve){console.log('立即执行for循环啦'); for(vari=0;i<10000;i++){i==99&&resolve(); }}).then(function(){console.log('executethenfunction')});console.log('代码执行结束'); 尝试按照我们上面刚学的JS执行机制来分析: setTimeout是异步任务,放在eventtable newPromise是同步任务,放在主进程,并直接执行并打印console.log('for循环即将执行') .then是一个异步任务,放在eventtable console.log('代码执行结束')是一段同步代码,放入主进程直接执行 所以,结果是:for循环立即执行---代码执行完成---定时器启动---执行函数是吗? 亲自执行后,结果不是这样的,而是:立即执行for循环---代码执行结束---执行then函数---定时器启动 那么,是不是异步任务的执行顺序,不是前后台的顺序,而是其他的规定呢?其实按照异步和同步的划分,是不准确的。 准确的划分方法是: macro-task(宏任务):包括整体代码脚本,setTimeout,setInterval micro-task(微任务):Promise,process.nextTick follow这个JS的执行机制是: 执行一个宏任务,如果过程中遇到微任务,会被放入微任务的“事件队列”中 当前宏任务执行完毕后,它会检查微任务的“事件队列”,并依次执行所有微任务。 重复上面2步,结合eventloop(1)eventloop(2),是比较准确的JS执行机制 尝试按照刚刚学习的执行机制,分析例子2: 先执行脚本下的宏任务,遇到setTimeout就放到宏任务的“队列”中 遇到newPromise就直接执行,打印“立即执行for循环” 遇到then方法,就是一个microtask,放入microtask的“queue”中 print"codeexecutioncompleted" 本轮macrotask执行完毕,查看本轮microtask,在then方法中找到一个函数,print"thenfunctionisexecuted" 这里,这一轮eventloop全部搞定了。 在下一个循环中,先执行一个宏任务,发现在setTimeout的“队列”中有一个函数宏任务,执行并打印“定时器已启动” 所以最终的执行顺序是:立即执行for循环---代码执行结束---执行then函数---定时器启动 4。这个setTimeout代码是什么意思?我们一般说:3秒后,setTimeout中的函数会被执行 setTimeout(function(){console.log('executed')},3000) 但是这个并不严谨,准确的解释是:3秒后,setTimeouteventqueue中的函数会被push到eventqueue中,eventqueue(事件队列)中的任务只会在主线程空闲时执行。 因此只有当(1)3秒后(2)主线程空闲且两者都满足时,函数才会在3秒后执行。10秒,那么这个函数只能在10秒后执行。
