简体   繁体   English

“事件循环队列”和“作业队列”有什么区别?

[英]What is the difference between "event loop queue" and "job queue"?

I can not understand how the following code run.我无法理解以下代码是如何运行的。 Why "1" is after "b" but "h" is after "3"?为什么“1”在“b”之后,而“h”在“3”之后? Should'n the order be: a, b, 1, 2, h, 3?顺序应该是:a、b、1、2、h、3? Some articles said that the difference between "event loop queue" and "job queue" leads to the following output.有文章说“事件循环队列”和“作业队列”的区别导致如下输出。 But how?但是怎么做? I have read the specification of ECMAScript 2015 - 8.4 Jobs and Job Queues , wanting to know how Promise'job works, but it makes me more confused.我已经阅读了ECMAScript 2015 - 8.4 Jobs and Job Queues的规范,想知道 Promise'job 是如何工作的,但这让我更加困惑。 Can someone help me?有人能帮我吗? Thank you!谢谢!

var promise = new Promise(function(resolve, reject) {resolve(1)});
promise.then(function(resolve) {console.log(1)});
console.log('a');
promise.then(function(resolve) {console.log(2);});
setTimeout(function() {console.log('h')}, 0);
promise.then(function(resolve) {console.log(3)});
console.log('b');

// a
// b
// 1
// 2
// 3
// h

I know Promise is asynchronous, but the callback of setTimeout(..) asynchronous operation is always after Promise's asynchronous operation.我知道 Promise 是异步的,但是 setTimeout(..) 异步操作的回调总是在 Promise 的异步操作之后。 Why?为什么?

Why "1" is after "b"?为什么“1”在“b”之后?

By promise specification, all promise .then() handlers are called asynchronously AFTER the current thread of JS has run to completion.根据promise 规范,所有promise .then()处理程序在JS 的当前线程运行完成.then()异步调用。 Thus, both a and b which are executed synchronously as part of the current JS will execute before any .then() handlers so 1 will always be after a and b .因此,作为当前 JS 的一部分同步执行的ab将在任何.then()处理程序之前执行.then()因此1将始终在ab

Some interesting reading: T asks, microtasks, queues and schedules and What is the order of execution in javascript promises and Writing a JavaScript framework - Execution timing, beyond setTimeout .一些有趣的阅读:T asks, microtasks, queues and schedulesWhat is the order of execution in javascript promisesWriting a JavaScript framework - Execution Timing, Beyond setTimeout


There's some good advice here in this thread: Promises wiggle their way between nextTick and setImmediate :在这个线程中有一些很好的建议:承诺在nextTicksetImmediate之间摆动

I would not recommend relying on the exact execution order of non-chained events.我不建议依赖非链式事件的确切执行顺序。 If you want to control the execution order — rearrange the callbacks in a way so that the one that you want to be executed later depends on the one that you want to be executed earlier, or implement a queue (that does the same behind the hood).如果您想控制执行顺序 — 以某种方式重新排列回调,以便您希望稍后执行的回调取决于您希望较早执行的回调,或者实现一个队列(在幕后执行相同的操作) )。

In other words, if you depend upon a particular timing of asynchronous events, then you should actually chain them in your code so one must happen after the other via your code rather than relying on unspecified scheduling in the implementation.换句话说,如果您依赖于异步事件的特定时间,那么您实际上应该将它们链接到您的代码中,这样一个事件必须通过您的代码一个接一个发生,而不是依赖于实现中未指定的调度。

In HTML terms, the event loop for a page or set of pages from the same domain can have multiple task queues .在 HTML 术语中,来自同一域的一个页面或一组页面的事件循环可以有多个任务队列 Tasks from the same task source always go into the same queue, with the browser choosing which task queue to use next.来自同一个任务源任务总是进入同一个队列,浏览器选择下一个要使用的任务队列。

Tasks to run timer call backs come from the timer task source and go in the same queue.运行计时器回调的任务来自计时器任务源并进入同一队列。 Let's call this queue task queue "A" .我们将此队列任务队列称为“A”

The ECMAscript 2015 (ES6) specification requires tasks to run Promise reaction callbacks to form their own job queue called "PromiseJobs" . ECMAscript 2015 (ES6) 规范要求任务运行 Promise 反应回调以形成它们自己的名为“PromiseJobs”的作业队列。 ECMAscript and HTML specifications do not use the same language, so let's notionally equate ECMA's "Promise Job queue" with HTML task queue "B" in the browser - at least a different queue to the one used by timers. ECMAscript 和 HTML 规范不使用相同的语言,所以让我们在概念上将 ECMA 的“Promise Job 队列”等同于浏览器中的 HTML任务队列“B” ——至少与计时器使用的队列不同。

Theoretically a browser could choose tasks from either queue A or B to run, but in practice the promise task queue gets higher priority and will empty before a timer call back gets run.理论上,浏览器可以从队列 A 或 B 中选择任务来运行,但实际上承诺任务队列获得更高的优先级,并且会在计时器回调运行之前清空。

This is why "h" gets logged last.这就是为什么最后记录“h”的原因。 Promise then calls on fulfilled promises place jobs in the promise queue, which get executed with higher priority than timer call backs. Promise then调用已完成的 Promise 将作业放在 Promise 队列中,这些任务以比计时器回调更高的优先级执行。 The promise queue only becomes empty after console.log(3) has been executed, which allows the timer call back to execute.只有在console.log(3)执行后,promise 队列才会变空,这允许定时器回调执行。


Advanced 先进的

ECMAScript guardians chose not to use HTML5 terminology or description of task queues in their specification because ECMAScript can run in more environments than just HTML browsers. ECMAScript 的守护者选择不在他们的规范中使用 HTML5 术语或任务队列描述,因为 ECMAScript 可以在更多环境中运行,而不仅仅是 HTML 浏览器。

Native implementation of promise queues may use a "micro task" queue instead of a separate dedicated promise task queue.承诺队列的本机实现可以使用“微任务”队列而不是单独的专用承诺任务队列。 Micro queued jobs are simply run after the current script thread and any tasks previously added to the micro queue complete.微队列作业只是在当前脚本线程和之前添加到微队列的任何任务完成后运行。

Detail of micro task queuing is not required to understand promises.理解promise不需要微任务队列的细节。

Promise polyfills for browsers which lack native support for promises (all versions of IE etc) may use timers and not behave in exactly the same way as native implementations when it comes to the order of promise reactions and timer call backs.对于缺乏原生支持承诺的浏览器(所有版本的 IE 等)的 Promise polyfills 可能会使用计时器,并且在涉及 Promise 反应和计时器回调的顺序时,其行为方式与本机实现的方式不同。

I found this one easy to understand for someone new to JS.我发现这个对于 JS 新手来说很容易理解。

This is copy paste from @getify's book这是@getify 书中的复制粘贴

to use a metaphor: the event loop queue is like an amusement park ride, where once you finish the ride, you have to go to the back of the line to ride again.用一个比喻:事件循环队列就像一个游乐园的游乐设施,一旦你完成了游乐设施,你必须到队伍的后面再骑一次。 But the Job queue is like finishing the ride, but then cutting in line and getting right back on.但是工作队列就像完成骑行,然后插队并重新开始。

event loop queue - for all async callbacks other than promises, h事件循环队列 - 对于除 promises 之外的所有异步回调,h

job queue - for all async callbacks related to promises.作业队列 - 所有与承诺相关的异步回调。 1, 2, 3 1、2、3

Sync - a, b同步 - a, b

ES6 has 2 queues ES6 有 2 个队列

  1. CallBack queue回调队列
  2. Job queue (Micro-task queue)作业队列(微任务队列)

Both setTimeout and a promise are async code. setTimeout 和 promise 都是异步代码。

In setTimeout we explicitly specify the function to be auto-run when the background web browser api work is finised (in setTimeout's case its the Timer feature of web browser api), once the timer has done its job it pushes the function onto the callback queue and has to wait until all the sync code of js has completed, thats why在 setTimeout 中,我们明确指定当后台 Web 浏览器 api 工作完成时要自动运行的函数(在 setTimeout 的情况下,它是 Web 浏览器 api 的 Timer 功能),一旦定时器完成它的工作,它会将函数推送到回调队列并且必须等到js的所有同步代码完成,这就是为什么

console.log("a")
console.log("b")

gets done first先完成

Now coming to the promise part, any promise in JS does 2 things现在来到承诺部分,JS 中的任何承诺都会做两件事

  1. Sets the background api feature设置后台api功能
  2. returns a promise object返回一个承诺对象

the .then() specifies which function to be run once the promise has been resolved , but not immediately .then()指定一旦 promise 被解决后要运行的函数,但不是立即运行

The function specified inside the .then() gets pushed inside the Job queue on task completion .then()中指定的函数在任务完成时被推送到作业队列

Once all the sync code in JS is completed, the event loop checks the job queue first and then the callback queue So thats why 'h' is logged at the very end一旦 JS 中的所有同步代码完成,事件循环首先检查作业队列,然后检查回调队列所以这就是为什么最后会记录 'h'

As of Es6, job queue runtime added to accommodate the promises.从 Es6 开始,添加了作业队列运行时以适应承诺。 with new Promise() we handle async code natively.使用new Promise()我们本地处理异步代码。 setTimeout is not part of javascript, it is part of the web api which is provided by the browser. setTimeout不是 javascript 的一部分,它是浏览器提供的 web api 的一部分。

Now we have two queues.现在我们有两个队列。 callback queue and job queue .回调队列作业队列 Job queue is also called micro task queue.作业队列也称为微任务队列。

The key thing is here, JOB QUEUE HAS HIGHER PRIORITY OVER CALLBACK QUEUE.关键在这里,作业队列比回调队列具有更高的优先级。 so in your example, first synchronous code is executed.所以在你的例子中,第一个同步代码被执行。

 console.log('a');  // a
 console.log('b');  // b

then promises are sent to the job queue and setTimeout() is sent to the callback queue.然后 promise 被发送到作业队列, setTimeout() 被发送到回调队列。 Now event loop, checks the job queu first regardless how long is the setTimeout() is set for.现在事件循环,首先检查作业队列,不管 setTimeout() 设置了多长时间。 since queue implements "first in first out" they are executed as they are ordered since they are just logging to the console.由于队列实现了“先进先出”,因此它们按顺序执行,因为它们只是登录到控制台。

promise.then(function(resolve) {console.log(1)}); // 1
promise.then(function(resolve) {console.log(2)}); // 2
promise.then(function(resolve) {console.log(3)}); // 3 

after job queue is cleared out, event loop checks the callback queue作业队列清除后,事件循环检查回调队列

setTimeout(function() {console.log('h')}, 0); // h

In Javascript Runtime The Job Queue is created with Task Queue during the Java Script Runtime which is much similar to task queue but has priority over the task queue which means javascript event loop first look in to the job queue if there is any task in the job queue the event loop will check the stack if stack is empty it will push the task in the stack from job queue after that event loop check again job queue if job queue is empty now event loop check task queue if there is any task the task will be pushed to stack for execution.在 Javascript 运行时作业队列是在 Java 脚本运行时使用任务队列创建的,它与任务队列非常相似,但优先于任务队列,这意味着如果作业中有任何任务,javascript 事件循环首先查看作业队列排队事件循环将检查堆栈如果堆栈为空它将在该事件循环之后将任务从作业队列推送到堆栈中如果作业队列为空则再次检查作业队列现在事件循环检查任务队列是否有任何任务将执行被压入堆栈执行。 The job queue is added in Java Script Run time in the es6 for the execution of promises在 es6 的 Java Script Run time 中添加了作业队列,用于 promise 的执行

for example :例如 :

var promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('promise win')
    }, 4000)
})
promise.then((result) => {
    console.log(result)
})
setTimeout(() => {
    console.log('setTimeout win')
}, 4000)

Output:输出:

promise win承诺赢

setTimeout win设置超时获胜

Explanation:解释:

both the setTimeout and promise are executed asynchronously and both take same amount of time but promises are executed first then callback , this is because promise are move to job queue and setTimeout is moved to callBack queue from the Web Api which is basically create during javascript runtime to perform tasks asynchronously and so Job Queue has priority over the task queue setTimeout 和 promise 都是异步执行的,并且都花费相同的时间,但是 promise 先执行然后回调,这是因为 promise 被移动到作业队列,而 setTimeout 被移动到 Web Api 的回调队列,这基本上是在 javascript 运行时创建的异步执行任务,因此作业队列优先于任务队列

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 回调队列和事件队列有什么区别? - What is the difference between callback queue and event queue? 浏览器中的事件循环和任务队列之间有区别吗? - Is there a difference between event loop and task queue in browsers? 事件队列和任务队列之间有什么区别吗? - Is there any difference between event queue and task queue? javascript promises,事件循环和作业队列 - javascript promises, the event loop, and the job queue 浏览器中的事件循环如何同时处理事件队列、作业队列、渲染队列? - How does the event loop in the browser deal with the event queue, job queue, render queue at the same time? 当进入 javascript 事件循环时,作业队列究竟是什么? - What exactly is a job queue when it gets to javascript event looping? JavaScript 事件循环:队列 vs 消息队列 vs 事件队列 - JavaScript Event Loop: Queue vs Message Queue vs Event Queue .queue()和jquery.queue()之间的区别 - Difference between .queue() and jquery.queue() 回调、高阶函数、回调队列有什么区别 - What is the difference between callback, high-order functions, and callback queue 在javascript运行时中,堆栈的“框架”与队列的“消息”之间有什么区别? - In javascript runtime, what is the difference between a “frame” of the stack and a “message” of the queue?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM