本文通过实例给大家详细分析了JS中事件循环机制的原理和用法,以下是全部内容:
var=new开始日期() setTimeout(函数(){ var=new结束日期 控制台。日志(时间:,结束,开始,“女士”) },500) 而(新日期()——开始& lt;1000){ }
有其他语言能完成预期的功能吗? Java,在Java.util.Timer中,对于定时任务的解决方案是通过多线程手段实现的,任务对象存储在任务队列,由专门的调度线程,在新的子线程中完成任务的执行
<强> js是单线程的强>
JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。
为了利用多核CPU的计算能力,HTML5提出网络工作者标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
函数调用栈和任务队列
<强>调用栈强>
JS执行时会形成调用栈,调用一个函数时,返回地址,参数,本地变量都会被推入栈中,如果当前正在运行的函数中调用另外一个函数,则该函数相关内容也会被推入栈顶。该函数执行完毕,则会被弹出调用栈。变量也随之弹出,由于复杂类型值存放于堆中,因此弹出的只是指针,他们的值依然在堆中,由GC决定回收。
事件循环(事件循环),任务队列(任务队列)
JavaScript主线程拥有一个执行栈以及一个任务队列
遇到异步操作(例如:setTimeout (AJAX)时,异步操作会由浏览器(OS)执行,浏览器会在这些任务完成后,将事先定义的回调函数推入主线程的任务队列任务队列中,当主线程的执行栈清空之后会读取任务队列中的回调函数,当任务队列被读取完毕之后,主线程接着执行,从而进入一个无限的循环,这就是事件循环。
主线程执行栈,任务队列循环执行,构成事件循环
<强>结论强>
setTimeout()只是将事件插入了“任务队列”,必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。
另一个例子
(功能测试(){ setTimeout(函数(){console.log (4)}, 0); 新的承诺(功能执行者(解决){ console.log (1); (var=0;i<10000;我+ +){ 我==9999,,解决(); } console.log (2); })(函数(){ console.log (5); }); console.log (3); })()
<强> Macrotask,Microtask 强>
macrotask和microtask是异步任务的两种分类。在挂起任务时,JS引擎会将所有任务按照类别分到这两个队列中,首先在macrotask的队列(这个队列也被叫做任务队列)中取出第一个任务,执行完毕后取出microtask队列中的所有任务顺序执行,之后再取macrotask任务,周而复始,直至两个队列的任务都取完。
macro-task:脚本(整体代码),setTimeout, setInterval, setImmediate, I/O, UI呈现
micro-task:过程。nextTick承诺(这里指浏览器实现的原生承诺),对象。观察,MutationObserver
<强>结论
强>
全部代码(脚本)macrotask→microtask队列(含有promise.then)→macrotask (setTimeout)→下一个microtask
节点。js的事件循环
的过程。nextTick,setImmediate
的过程。nextTick指定的任务总是发生在所有异步任务之前
setImmediate指定的任务总是在下一次事件循环时执行
的过程。nextTick(函数(){ console.log (1); 的过程。nextTick(函数B () {console.log (2);}); }); setTimeout(超时函数(){ 控制台。日志(“超时解雇”); },0)
新的承诺(函数(解决){ console.log (“glob1_promise”); 解决(); })(函数(){ console.log (“glob1_then”) }) process.nextTick(函数(){ console.log (“glob1_nextTick”); })实例分析js事件循环机制