本文介绍了如何利用JavaScript和Node.js中的事件循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我正在寻找具体例子,以清楚理解以下内容: 如何/何时可以利用 JavaScript 中的事件循环? 关于事件循环的 ECMAScript-6/2015 中引入的任何更改? 附录: 请考虑以下代码: var list = readHugeList(); var nextListItem = function(){ var item = list.pop(); if(item){ //处理列表项... setTimeout(nextListItem,0); } };假设setTimeout()这里使用事件循环来防止stackoverflow,是否正确?我读了这个代码的解释: 更新2 对于上面代码中的setTimeout()如下:解释中的矛盾,上述和这里的答案正在使它变得更加难以理解。解决方案 其最高水平,一般。但是,不同的环境将不同的细节实现细节,真正需要环境特定的信息来了解发生了什么。所有的血液细节都在规范中,主要是在作业和作业排队。 有几个关键方面: >作业(JavaScript规范的术语)或任务(如HTML规范所称),等待JavaScript引擎运行。当发动机完成作业时,它会在队列中的下一个作业/任务(如果有的话)上起作用。 一旦作业开始,它一直运行直到完成;没有其他工作可以中断它。这被称为运行完成,对JavaScript的工作原理非常重要。 处理作业队列 请考虑以下代码: 的console.log( 1); setTimeout(function(){ console.log(two); },1000); 如果您运行该代码(通过NodeJS或浏览器),则会发生什么(省略一些不相关的详细信息): 开始时,队列为空,JavaScript引擎空闲 环境(NodeJS,浏览器)排队作业运行脚本 JavaScript引擎拾取作业并运行脚本: 它输出一个 它为我们给 setTimeout 的匿名函数设置一个计时器 作业结束 在某些时候,环境中的定时器机制决定是时候调用回调,所以它排队一个工作来调用它 JavaScript引擎从队列中获取该作业并运行函数 它输出两个 作业结束 现在考虑这个代码: console.log(Date.now ),一); setTimeout(function first(){ console.log(Date.now(),two); },500); setTimeout(function second(){ var end = Date.now()+ 1000; while(end> Date.now()){ // Busy-等待(通常这是一个坏事,我在这里使用 //来模拟需要大量时间的实际工作} },100); 正如你所看到的,它调度一个定时回调500ms,然后另一个在100ms,但在100ms的回调代码将需要至少1000ms才能运行,会发生什么? 环境排队作业运行脚本 JS引擎选择这个工作 输出时间值和一个,说 1470727293584一个 将来为500ms的第一个设置定时回调 将功能 second 定时回调 作业结束 大约100ms后,环境将作业排队运行第二个 JavaScript引擎拾取作业并运行函数 开始做工作(好的,真的只是忙着等待) 大约400ms后时间设置定时器),环境队列作业调用首先;由于JavaScript引擎正忙于上一个作业,所以该作业位于队列中。 同时,JavaScript引擎仍然在调用第一个 最终,#3的JavaScript引擎完成的工作已完成 作业完成 JavaScript引擎从队列中选择下一个作业,并将调用运行到 second 输出时间值和两,如 1470727294687两个 作业结束 请注意环境在JavaScript忙时执行某些操作;它排队了要完成的工作。 在JavaScript引擎正忙的时候,环境可以做的事情非常重要。 (值得注意的是,当排队作业时,某些环境可能不一定会在队列的端之间添加任务;在某些浏览器中,例如队列实际上是一个具有稍微不同优先级的队列...)它不是很有用,因为知道它在那里。同样重要的是要注意,虽然JavaScript 具有运行到完成的语义,但运行环境的环境可能会同时执行其他操作,即使JavaScript代码正在运行。不是真的,虽然它在规范中的定义比以前更完整。可能最接近更改的内容与承诺有关:您计划的回调与然后或 catch 将始终排队等待作业,它将永远不会同步运行。这是JavaScript规范首次定义了异步发生的事情(ajax和timers不属于JavaScript规范)。 以下,您已询问:(我假设在此之后立即有一个 nextListItem(); 。) 不,但它做的其他重要事情。非 setTimeout 版本将如下所示: var list = readHugeList(); while(list.length){ var item = list.pop(); //处理列表项... } 这是一个简单的循环,没有堆栈溢出的潜力。 它正在做的是与事件循环协同工作,避免了一个真正长期运行的工作,将绑定JavaScript引擎,阻止它处理任何其他作业(如I / O完成,点击或其他事件)。因此,它通过一次处理一个项目将工作打破小作业,有助于确保整个作业队列不断得到处理。这意味着处理列表需要更长的时间,但是在执行此操作时不会阻止其他操作。 1 确实,代码的非 setTimeout 版本可能如下所示: var list = readHugeList(); var nextListItem = function(){ var item = list.pop(); if(item){ //处理列表项... // then recurse nextListItem(); } }; nextListItem(); ...在这种情况下,有堆栈溢出的潜力,但这将是一个非常奇怪写这个代码的方法。 I am looking for detailed explanations with examples to clearly understand the following:How/when should/can I leverage event loop in JavaScript?Any changes introduced in ECMAScript-6/2015 regarding event loop?Addendum:Consider the following code:var list = readHugeList();var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... setTimeout( nextListItem, 0); }};Is it correct to assume setTimeout() here uses the event loop to prevent stackoverflow? I read an explanation for this code that:Update 2The full explanation given for the setTimeout() in the code above is as follows:The contradiction in explanations, aforementioned and in the answers here, is making it all the more difficult to understand. 解决方案 At its highest level, general. But different environments will implement the details so differently that really you need environment-specific information to know what's going on.All the gory details are in the specification, chiefly in the section called Jobs and Job Queues.There are a couple of keys aspects:There is a queue of jobs (the JavaScript spec's term) or "tasks" (as the HTML spec calls them) waiting to be run by the JavaScript engine. When the engine finishes a job, it's put to work on the next job/task in the queue, if any.Once a job is started, it keeps running until it's done; no other jobs can interrupt it. This is called run-to-completion and is very important to the definition of how JavaScript works.The job queue is processed in order.So consider this code:console.log("one");setTimeout(function() { console.log("two");}, 1000);If you run that code (via NodeJS or a browser), here's what happens (omitting some irrelevant details):At the beginning, the queue is empty and the JavaScript engine is idleThe environment (NodeJS, the browser) queues a job to run the scriptThe JavaScript engine picks up the job and runs the script:It outputs "one"It sets a timer for the anonymous function we gave to setTimeoutThe job endsAt some point, the timer mechanism in the environment determines that it's time to call the callback, so it queues a job to call itThe JavaScript engine picks up that job from the queue and runs the functionIt outputs "two"The job endsNow consider this code:console.log(Date.now(), "one");setTimeout(function first() { console.log(Date.now(), "two");}, 500);setTimeout(function second() { var end = Date.now() + 1000; while (end > Date.now()) { // Busy-wait (normally this is a Bad Thing™, I'm using it here // to simulate actual work that takes significant time }}, 100);As you can see, it schedules a timed callback at 500ms and then another at 100ms. But the code in the callback at 100ms will take at least 1000ms to run. What happens?The environment queues a job to run the scriptThe JS engine picks that job upOutputs the time value and "one", say 1470727293584 oneSets a timed callback to the function first for 500ms in the futureSets a timed callback to the function second for 100ms in the futureThe job endsAbout 100ms later, the environment queues a job to run secondThe JavaScript engine picks up the job and runs the functionIt starts doing work (okay, so really it's just busy waiting)About 400ms later (500ms from the time the timer was set), the environment queues a job to call first; since the JavaScript engine is busy with the previous job, the job sits in the queueMeanwhile, the JavaScript engine is still working on the job calling first:Eventually the work being done by the JavaScript engine from #3 is doneThe job finishesThe JavaScript engine picks up the next job from the queue and runs the call to secondIt outputs the time value and "two", say 1470727294687 twoThe job endsNote that the environment did something while JavaScript was busy; it queued a job to be done.The fact that the environment can do things while the JavaScript engine is busy is very important.(It's worth noting that when queuing jobs, some environments may not necessarily add the job at the end of the queue; in some browsers, for instance, "the queue" is actually more than one queue with slightly different priorities...)It's not so much leveraging it as knowing it's there. It's also important to note that while JavaScript has run-to-completion semantics, the environment in which it's running may be doing other things at the same time, even while the JavaScript code is running.Not really, although it's defined much more completely in the spec than previously. Probably the closest thing to a change is in relation to promises: The callback you schedule with then or catch will always be queued as a job, it will never be run synchronously. That's the first time the JavaScript specification has defined something that happens asynchronously (ajax and timers are not part of the JavaScript spec).Below, you've asked:(I assume there's a nextListItem(); call immediately after that.)No, but it's doing something else important. The non-setTimeout version of that would look something like this:var list = readHugeList();while (list.length) { var item = list.pop(); // process the list item...}That's a simple loop, there's no potential for stack overflow.What it's doing is working cooperatively with the event loop, avoiding having a really long-running job that would tie up the JavaScript engine, preventing it processing any other jobs (such as I/O completions, clicks, or other events). So it's breaking the work up into small jobs by processing the items one at a time, helping ensure that the overall job queue keeps getting processed. That means it takes a lot longer to process the list, but doesn't block other things while doing so. It's true that the non-setTimeout version of that code could look like this:var list = readHugeList();var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... // then recurse nextListItem(); }};nextListItem();...and in that case, there's potential for stack overflow, but it would be a very odd way to write that code. 这篇关于如何利用JavaScript和Node.js中的事件循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-03 15:10