当前位置: 首页 > 科技观察

怎么玩转JavaScript事件循环

时间:2023-03-16 18:05:58 科技观察

听了很多JavaScript单线程、异步、V8之后,你会想知道JavaScript是如何使用单线程来实现所谓异步的。参考了一些文章,学到了一个很重要的词汇:事件循环(EventLoop)。其中有:阮一峰老师的《JavaScript运行机制详解:再说事件循环》PhilipRoberts的《事件循环到底是什么?ErinSwenson-Healey的TheJavaScriptEventLoop:Explained等这些文章都很不错,让我对EventLoop的机制有了一个大概的了解。异步在JavaScript中的重要性也意味着理解EventLoop的必要性,否则你怎么敢轻易使用setTimeout和setInterval。这里我通过翻译一篇文章来解释EventLoop。原文请点这里WillsonMock:什么是JavaScript事件循环?下面的图片也引用自这篇文章。JavaScript引擎:就JavaScript引擎而言(原创写作时间:2014年7月5日),在各种JavaScript引擎的实现中,最著名的是GoogleChrome的V8引擎,可以在浏览器中使用,也可以通过NodeJS使用在服务器端使用。但是JavaScript引擎到底是做什么用的呢?它其实很简单——它的任务就是遍历应用程序中的每一行JavaScript代码,一次一行地执行,也就是说JavaScript是单线程的。这里最大的影响是:如果JavaScript代码中有一个地方占用时间比较长,后面的代码就会被阻塞。那么JavaScript引擎如何知道如何一次处理一行JavaScript代码呢?它使用调用堆栈。您可以将调用堆栈比作电梯——电梯中的第一个人将是最后一个出来的人,而电梯中的最后一个人将是最后一个出来的人。看个栗子:/*Withinmain.js*/varfirstFunction=function(){console.log("我是第一!");};varsecondFunction=function(){firstFunction();console.log("我是第二!");};secondFunction();/*结果:*=>I'mfirst!*=>I'msecond!*/下面是调用栈:1.Main.js执行2.调用secondFunction3.调用secondFunction导致调用firstFunction4。执行firstFunction,输出“我是第一个!”,然后因为执行了firstFunction,所以firstFunction会从调用栈中弹出。5.secondFunction继续执行,输出“我是第二!”。然后,因为secondFunction完成执行,secondFunction从调用堆栈弹出。6.***,main.js被执行,出栈。事件循环:了解了JavaScript引擎中调用栈的工作原理后,我们来看看如何使用异步回调函数来避免代码阻塞。(译者注:回调函数的实现方式有很多种,最常见的有:在函数中使用函数参数等。)setTimeout是使用的回调函数。看个栗子:/*Withinmain.js*/varfirstFunction=function(){console.log("I'mfirst!");};varsecondFunction=function(){setTimeout(firstFunction,5000);console.log("我是第一个!”);'msecond!");};secondFunction();/*结果:*=>I'msecond!*(And5secondslater)*=>I'mfirst!*/下面模拟调用栈(在前面栗子的基础上,我们在第二次push之前)1....2.secondFunction调用setTimeout,setTimeout被压入栈:3.setTimeout执行后,浏览器会将setTimeout回调函数(本例为firstFunction)放入Event中Table.EventTable是一个注册站:调用栈让EventTable注册一个5秒后会被调用的函数,当指定的事情发生时,EventTable会把这个函数移到EventQueue中。EventQueue其实就是一个函数等待被调用并移动到调用栈的缓冲区。问题是,函数什么时候会从EventQueue移动到调用栈?JavaScript引擎遵循一个规则:有一个监控进程(我不'知道要翻译成什么)会不断检查调用栈是否为emp泰。一旦为空,它就会检查EventQueue中是否有等待调用的函数。如果存在,它将调用此Queue中的第一个函数并将其移动到调用堆栈。如果EventQueue为空,监控进程会不定期的继续检查。这整个过程就是事件循环。4.一旦回调函数被添加到Event表中,代码就不会被阻塞,浏览器不会等待5秒才继续处理下一段代码。相反,浏览器会继续执行secondFunction中的下一行代码,console.log。5.在后台,EventTable会持续监控是否有事件触发,将函数移到EventQueue中。在这个栗子中,执行了secondFunction,然后也执行了main.js。6.回调函数放入事件表五秒后,事件表将第一个函数移动到事件队列。7.由于eventloop一直在监控调用栈是否为空,一旦发现调用栈为空,就会调用firstFunction并创建一个新的调用栈。8.firstFunction一旦执行,调用栈为空,EventTable中没有注册函数,EventQueue也为空。总结虽然这样的解释隐藏了实际JavaScript引擎、EventTable、EventQueue和EventLoop的具体实现细节,但是对于大多数人来说,我们只需要大致了解JavaScript执行异步函数时会发生什么。能。