本篇文章给大家带来的内容是关于JS运行机制:同步、异步以及事件循环(Event Loop)的分析,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
一、JS为什么是单线程的
Javascript语言的一大特点就是单线程,同一时间只能做同一件事,那么为什么JS不能多线程呢?
作为浏览器脚本语言,Javascript的主要用途是与用户互动,以及操作DOM,这决定了它只能是单线程,否则会带来很复杂的同步问题。比如:假定Javascript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了找个节点,这时浏览器应该以哪一个为准?
所以,为了避免复杂性,从一诞生,Javascript就是单线程,这已经成为了这门语言的核心特征,将来也不会改变。
为了利用多核CPU的计算能力,HTML5提出Web Woker标准,允许Javascript脚本创建多个线程,但是子线程完全受主线程控制,且不能操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
二、同步和异步
假设存在一个函数A:
A(args...){...}
同步:如果在调用函数A的时候,调用者立即能够得到预期的结果,那么这个函数就是同步的。
异步:如果在调用函数A的时候,调用者无法立即得到预期的结果,而是需要在将来通过一定的手段(耗时,延时,事件触发)得到,那么这个函数就是异步的。
三、JS是如何实现异步操作的
虽然JS是单线程的但是浏览器的内核是多线程的,浏览器为一些耗时任务开辟了另外的线程,不同的异步操作会由不同的浏览器内核模块调度执行,例如onlcik,setTimeout,ajax处理的方式都不同,分别是由浏览器内核中的DOM Bingding、network、timer模块执行,当执行的任务得到运行结果时,会将对应的回调函数放到任务队列中。所以说,JS是一直都是单线程的,实现异步操作的其实是浏览器。
在上图中,调用栈中遇到DOM请求、ajax请求以及setTimeout等WebAPIs的时候就会交给浏览器内核的其他模块进行处理,webkit内核在Javascript执行引擎之外,有一个重要的模块是webcoew模块。对于图中WebAPIs提到的三种API,webcore分别提供了DOM Binding、network、timer模块来处理底层实现。等到这些模块处理完这些操作的时候将回调函数放入任务队列中,之后等栈中的task执行完之后再去执行任务队列中的回调函数。
小结:
1、所有的代码都要通过函数调用栈中调用执行
2、当遇到前文中提到的APIs的时候,会交给浏览器内核的其他模块进行处理
3、任务队列中存放的是回调函数
4、等到调用栈中的task执行完之后再回去执行任务队列中的task
JS的运行机制如下:
(1)所有的同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个“任务队列”。只要异步任务有了运算结果,就在“任务队列“之中放置一个事件(回调函数)。
(3)一旦“执行栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态。进入执行栈,开始执行。
(4)主线程不断重复上面的第三步
任务队列
上文中一直都有提到任务队列,那么任务队列到底是个什么东东呢?举个例子
在ES6的标准中,任务队列分为宏任务(macro-task)和微任务(micro-task)
1.macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
2.micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver
事件循环的顺序是从script开始第一次循环,随后全局上下文进入函数调用栈,碰到macro-task就将其交给处理它的模块处理完之后将回调函数放进macro-task的队列之中,碰到micro-task也是将其回调函数放进micro-task的队列之中。直到函数调用栈清空只剩全局执行上下文,然后开始执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次执行macro-task中的一个任务队列,执行完之后再执行所有的micro-task,就这样一直循环。
接下来我们分析一下执行过程:
(function test() { setTimeout(function() {console.log(4)}, 0); new Promise(function executor(resolve) { console.log(1); for( var i=0 ; i<10000 ; i++ ) { i == 9999 && resolve(); } console.log(2); }).then(function() { console.log(5); }); console.log(3); })()
1、全局上下文入栈,开始执行其中的代码。
2、执行到setTimeout,作为一个macro-task交给timer模块处理完成后将其回调函数放入自己的队列中。
3、执行到Promise实例,将Promise入栈,第一个参数是在当前任务直接执行输出1。
4、执行循环体,遇到resolve函数,入栈执行后出栈,改变promise状态为Fulfilled,随后输出2
5、遇到then方法,作为micro-task,进入Promise的任务队列。
6、继续执行代码,输出3。
7、输出3之后第一个宏任务代码执行完毕,开始执行所有在队列之中的微任务。then的回调函数入栈执行后出栈,输出5。
8、这时候所有的micao-task执行完毕,第一轮循环结束。第二轮循环从setTimeout的任务队列开始,setTimeout的回调函数入栈执行完毕之后出栈,此时输出4。
小结:1、不同的任务会放进不同的任务队列之中。
2、先执行macro-task,等到函数调用栈清空之后再执行所有在队列之中的micro-task。
3、等到所有micro-task执行完之后再从macro-task中的一个任务队列开始执行,就这样一直循环。
4、当有多个macro-task(micro-task)队列时,事件循环的顺序是按上文macro-task(micro-task)的分类中书写的顺序执行的。
总结:
JS引擎在解析JS代码的时候,会创建一个主线程(main thread)和一个调用堆栈(call-stack),在对一个调用堆栈中的task处理的时候,其他的都要等着。
当执行到一些异步操作的时候,会交给浏览器内核的其他模块处理(以webkit为例,是webcore模块),处理完成将task(回调函数)放入任务队列中。
一般不同的异步任务的回调函数都会放入不同的任务队列中,等到调用栈中所有的task执行完毕,接着去执行任务队列中的task(回调函数)
相关文章推荐:
以上是JS运行机制:同步、异步以及事件循环(Event Loop)的分析的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript是现代网站的核心,因为它增强了网页的交互性和动态性。1)它允许在不刷新页面的情况下改变内容,2)通过DOMAPI操作网页,3)支持复杂的交互效果如动画和拖放,4)优化性能和最佳实践提高用户体验。

C 和JavaScript通过WebAssembly实现互操作性。1)C 代码编译成WebAssembly模块,引入到JavaScript环境中,增强计算能力。2)在游戏开发中,C 处理物理引擎和图形渲染,JavaScript负责游戏逻辑和用户界面。

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

螳螂BT
Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)