摘要:单线程的好处简单,处理时不会出现并发竞争问题异步的必要性让用户体验更流畅如何实现异步见参考,,调用栈函数执行上下文。单线程只能有一个并且每次只能执行一个任务。
参考:
JavaScript 运行机制详解:再谈Event Loop
深入理解JavaScript的执行过程--单线程的JS
细说JavaScript单线程的一些事
The JavaScript Event Loop: Explained
模拟Event Loop执行过程
Node.js 事件循环一: 浅析
理解 Event Loop、Micro Task & Macro Task
HTML系列:macrotask和microtask
1. js为啥是单线程执行单线程是指只在一个线程里执行JS代码,但浏览器是多线程的。
1.1 单线程的好处简单,处理DOM时不会出现并发竞争问题
2. 异步的必要性让用户体验更流畅
3. 如何实现异步:Event Loop见参考1,4,5
函数执行上下文。控制执行函数的调用执行。单线程只能有一个call statck, 并且每次只能执行一个任务。栈是有尺寸的,即在一次执行中函数的嵌套调用数量是有限的,如果超过这个限制就会报错。JS执行时遇到这种错误"Uncaught RangeError: Maximum call stack size exceeded"就是说明call statck溢出了。回调函数上限数量取决于statck本身的大小以及statck元素的大小->见参考:
function computeMaxCallStackSize1() { try { return 1 + computeMaxCallStackSize1(); } catch (e) { // Call stack overflow return 1; } } // 多了形参p,call stack元素就多占了内存 function computeMaxCallStackSize2(p) { try { return 1 + computeMaxCallStackSize2(); } catch (e) { // Call stack overflow return 1; } } console.log(computeMaxCallStackSize1()); // 两个输出结果不一样 console.log(computeMaxCallStackSize2());3.2 回调队列(callback queue)
看参考图,生动的动画模拟可以见参考5。当call stack空的时候,主线程查看callback队列里是否有异步任务,如果有则取出执行,执行完后(即call stack变空了)再去查看call back队列是否有异步任务。这个是循环的过程,也叫事件循环(event loop)。
while (queue.waitForMessage()) { queue.processNextMessage(); }
个人认为事件队列主要实现了异步回调功能。
3.3 非阻塞I/O首先明确一点,JS本身就没有I/O(网络请求,磁盘读写,用户交互)的,所有的I/O操作都是由宿主执行的,宿主提供相关的API供JS调用。当JS调用IO API时并不会等待宿主的执行结果而是继续执行后面的代码,当IO执行完成后宿主再通知JS,即在eventQueue中插入回调task。
不过还有些I/O是同步的,比如同步XHR请求,alert。尽量避免使用。
event loop实现了异步回调,但回调只能一个一个的执行,但前面的一个回调非常耗时时就会阻塞后面的回调执行,用户交互也可能出现卡死。
function sleep(ms) { var curr = Date.now(); while(Date.now() - curr < ms){}; } console.log(1) setTimeout(function(){ // 回调依旧被阻塞 console.log(2) }, 0) sleep(2000)
最好开启新线程执行耗时的运算(使用web worker)或者放在服务端运算。
4. Macro-task & micro-taskevent loop中除了 callback queue(macro-task)外还有个队列专门处理micro-task。micor-task队列为空时才去处理macro-task队列执行。
当打算以同步的方式处理异步回调(即执行栈为空时立马执行回调函数)时可以采用micro-task方式。
macrotasks: setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering
microtasks: process.nextTick, Promises, Object.observe, MutationObserver
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/93324.html
摘要:通过向消息池发送各种消息事件通过处理相应的消息事件。子线程往消息队列发送消息,并且往管道文件写数据,主线程即被唤醒,从管道文件读取数据,主线程被唤醒只是为了读取消息,当消息读取完毕,再次睡眠。 目录介绍 6.0.0.1 谈谈消息机制Hander作用?有哪些要素?流程是怎样的? 6.0.0.2 为什么一个线程只有一个Looper、只有一个MessageQueue,可以有多个Handle...
阅读 3060·2021-09-22 15:59
阅读 1312·2021-08-30 09:46
阅读 2275·2019-08-30 15:54
阅读 2010·2019-08-26 12:15
阅读 2536·2019-08-26 12:09
阅读 1334·2019-08-26 11:57
阅读 3337·2019-08-23 17:11
阅读 1882·2019-08-23 15:59