摘要:了解事件循环机制有助于理解的执行过程,同时这也是面试常见题。那么这个回调函数将在何时由谁执行呢已知是浏览器环境提供的,因此浏览器将对它进行处理,浏览器会在本次事件完成,即计时结束后,将回调函数加入循环队列中,然后等待被加入执行栈执行。
如果有人问JavaScript是什么,也许你会说它是一个单线程、非阻塞、异步、解释型的脚本语言。那么作为一个单线程语言,它是怎么实现非阻塞、异步的?这就涉及到了浏览器的事件循环机制,事件循环并非由ECMAScript定义,而是在HTML Standard中定义。了解事件循环机制有助于理解JS的执行过程,同时这也是面试常见题。
在浏览器中,浏览器会提供JavaScript的运行环境,如Chrome的V8,以及一些Web API,如DOM、Ajax、setTimeout等。
如图,在运行环境中存在一个执行栈stack,为当前正在执行的JS代码,当调用一个普通函数时,会生成新的作用域,并入栈,待执行结束后出栈,此时不涉及异步操作。但是当调用了异步函数时,情况就有所不同了,以setTimeout为例,当调用了setTimeout后,回调函数将在一段时间后才执行,由于JavaScript是异步,它不会等待回调函数执行,而是会立即获得结果并从上至下继续执行代码。那么这个回调函数将在何时由谁执行呢?已知setTimeout是浏览器环境提供的API,因此浏览器将对它进行处理,浏览器会在本次事件完成,即计时结束后,将回调函数加入循环队列task queue中,然后等待被加入执行栈执行。
循环队列中的任务被调用的时机,是当执行栈为空,即当前事件执行结束后,此时浏览器会查看循环队列是否为空,在非空时以FIFO的方式调用队列中的事件,加入执行栈,当执行栈再次为空时,再从循环队列中查找任务,这就形成了事件循环event loop,浏览器通过该机制让单线程的JS可以执行异步任务。这就可以解释一些很常见的关于setTimeout执行顺序的面试题。除了setTImeout外,常见的task任务源还有setInterval、setImmediate、I/O、UI rendering、XMLHttpRequest等。
除了以上普通的task,浏览器还引入了microtask的概念,microtask存储在microtask queue中,它的执行时机与task不同,当执行栈为空时,优先调用microtask中的任务执行,因此只有当microtask queue为空时,才会调用循环队列中的任务。常见的microtask源有promise、process.nextTick,关于promise的执行时机,也是面试较为常见的问题。
接下来就以一段代码的执行过程为例,解释event loop。
1 console.log(1); 2 setTimeout(() => {console.log(5)}, 0); 3 let promise = new Promise((resolve, reject) => { console.log(2) resolve() }) 4 promise.then(() => {console.log(4)}); 5 console.log(3)
请问以上代码的执行结果?
我们试着缕一缕这些代码的执行顺序,首先这一整段代码会被加入执行栈中,然后从上至下依次解释执行
1:直接输出1
2:此时调用了setTimeout,因此回调函数会在0ms后加入到循环队列中
3:此时实例化了一个promise,会立即执行实例化时的代码,因此会输出2
4:此时调用了promise的then方法,该方法的回调函数会被加入到microtask queue中
5:直接输出3
到此,执行栈执行结束,此时根据事件循环机制,首先查看microtask queue是否为空,会发现队列中有promise.then方法加入的回调函数,将其调入执行栈执行,输出4。执行栈再次执行结束,再查看microtask queue,此时为空,接着查看任务队列task queue,会发现由setTimeout方法加入的回调函数,调入执行栈执行,输出5。因此最后的输出顺序是 1 -> 2 -> 3 -> 4 -> 5
以上是关于浏览器端事件循环的个人理解,为什么要强调是浏览器端,因为从以上解释可以看出JS只是运行在浏览器提供的执行环境中,事件循环其实是由浏览器环境实现的,除了浏览器,还有Node环境,而Node环境与浏览器环境又有着许多差别,Node环境中的事件循环与浏览器端存在一些差异,待有空了再写一篇关于Node环境中的事件循环。关于浏览器事件循环,可以观看https://www.youtube.com/watch...
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/105138.html
摘要:如果当前没有事件也没有定时器事件,则返回。相关资料关于的架构及设计思路的事件讨论了使用线程池异步运行代码。下一篇初窥事件机制的实现二中定时器的实现 在浏览器中,事件作为一个极为重要的机制,给予JavaScript响应用户操作与DOM变化的能力;在Node.js中,事件驱动模型则是其高并发能力的基础。 学习JavaScript也需要了解它的运行平台,为了更好的理解JavaScript的事...
摘要:心塞塞根据规范,事件循环是通过任务队列的机制来进行协调的。等便是任务源,而进入任务队列的是他们指定的具体执行任务回调函数。然后当前本轮的结束,主线程可以继续取下一个执行。 依然是:经济基础决定上层建筑。 说明 首先,旨在搞清常用的同步异步执行机制 其次,暂时不讨论node.js的Event Loop执行机制,以下关于浏览器的Event Loop执行机制 最后,借鉴了很多前辈的研究文...
摘要:主线程要明确的一点是,主线程跟执行栈是不同概念,主线程规定现在执行执行栈中的哪个事件。主线程循环即主线程会不停的从执行栈中读取事件,会执行完所有栈中的同步代码。以上参考资料详解中的事件循环机制中的事件循环运行机制详解再谈 showImg(https://segmentfault.com/img/remote/1460000015317437?w=1920&h=1080); 前言 大家都...
摘要:曾经的理解首先,是单线程语言,也就意味着同一个时间只能做一件事,那么为什么不是多线程呢这样还能提高效率啊假定同时有两个线程,一个线程在某个节点上编辑了内容,而另一个线程删除了这个节点,这时浏览器就很懵逼了,到底以执行哪个操作呢所以,设计者把 Event Loop曾经的理解 首先,JS是单线程语言,也就意味着同一个时间只能做一件事,那么 为什么JavaScript不是多线程呢?这样还能提...
摘要:前沿是基于引擎的运行环境具有事件驱动非阻塞等特点结合具有网络编程文件系统等服务端的功能用库进行异步事件处理线程的单线程含义实际上说的是执行同步代码的主线程一个程序的启动不止是分配了一个线程,而是我们只能在一个线程执行代码当出现资源调用连接等 前沿 Node.js 是基于V8引擎的javascript运行环境. Node.js具有事件驱动, 非阻塞I/O等特点. 结合Node API, ...
摘要:深入理解引擎的执行机制灵魂三问为什么是单线程的为什么需要异步单线程又是如何实现异步的呢中的中的说说首先请牢记点是单线程语言的是的执行机制。 深入理解JS引擎的执行机制 1.灵魂三问 : JS为什么是单线程的? 为什么需要异步? 单线程又是如何实现异步的呢? 2.JS中的event loop(1) 3.JS中的event loop(2) 4.说说setTimeout 首先,请牢记2...
阅读 3637·2021-10-11 11:09
阅读 1318·2021-09-24 10:35
阅读 3402·2021-07-29 13:48
阅读 422·2019-08-30 13:15
阅读 2486·2019-08-30 12:53
阅读 3106·2019-08-30 12:44
阅读 2673·2019-08-29 16:57
阅读 942·2019-08-29 12:26