事件循环比回调队列更喜欢微任务队列? [英] event loop prefers microtask queue over callback queue?

查看:91
本文介绍了事件循环比回调队列更喜欢微任务队列?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在测试JS中的异步代码的概念.在回调队列和微任务队列顺序.每当promise对象得到解析时,实现方法{then}就会被推送到微任务队列中,而浏览器计时器函数的回调(例如setTimeout)会被推送到回调队列中.事件循环不断检查队列,并在调用堆栈为空时将函数从队列推入调用堆栈.事件循环应该比常规回调队列更喜欢微任务队列,但是在示例中: https://jsfiddle.net/BHUPENDRA1011/2n89ftmp/否则.

I was testing out concepts of asynchronous code in JS . Got confused between callback queue & microtask queue order. Whenever promise objects gets resolved , the fulfillment method { then } is pushed into microtask queue while the callbacks of browser timer functions such as setTimeout is pushed into callback queue. Event loop continuously checks queue and pushes functions from queue into call stack whenever call stack gets empty. Event loop should prefer microtask queue over normal callback queue but in the example : https://jsfiddle.net/BHUPENDRA1011/2n89ftmp/ it's happening otherwise.

function display(data) {
    console.log('hi back from fetch');
}

function printHello() {
    console.log('hello');
}

function blockfor300ms() {
    for (let i = 0; i < 300; i++) {
        // just delaying logic
    }
}
// this sets the printHello function in callback queue { event loop queue }
setTimeout(printHello, 0);

const futureData = fetch('https://api.github.com/users/xiaotian/repos');
// after promise is resolved display function gets added into other queue : Microtask queue { job queue}
futureData.then(display);
// event loop gives prefrence to Microtask queue ( untill  its complete) 

blockfor300ms();
// which runs first 
console.log('Me first !')

预期产量

  • 我第一!
  • 从获取中回来
  • 你好

实际输出:

  • 我第一!
  • 你好
  • 从获取中回来

请告诉我这是怎么回事.

Kindly let me know how it's happening over here.

谢谢

推荐答案

恭喜!您一定会参加Will Sentence的前端大师课程"JavaScript:新的硬性部分​​"! :)

I see you must be taking Will Sentence's Front-End Masters course "JavaScript: The New Hard Parts", congrats! :)

很棒的课程,以及测试此示例的荣誉.

Great course, and kudos for testing this example.

现在为您解释:

虽然是事实,但"kib"表示什么:

While it is true, what "kib" stated:

您的函数blockfor300ms不会将线程阻塞足够长的时间 提取以接收响应"

"your function blockfor300ms doesn't block the thread long enough for the fetch to receive a response"

不幸的是,这无关紧要,因为即使您直到收到对fetch调用的响应之后才阻止执行,您仍然会看到相同的结果... (请参见下面的示例代码片段,您可以使用警报框或长时间循环的非异步XMLHttpRequest调用来阻止执行,我收到的结果相同)

sadly this is irrelevant, because even if you did block execution until after you received a response to your fetch call, you would still see the same result... (see sample code snippet below, you can block execution with an alert box or a long loop of non-async XMLHttpRequest calls, I received the same result)

不幸的是,抓取无法按照我发现的所有博客和资源的描述进行操作...说明

Unfortunately, fetch does not work as described by all the blogs and resources I've found... which state that

Fetch会将其诺言链添加到微任务队列中,并在事件循环的下一个刻度之前的任何回调之前运行.

Fetch will add it's promise chain to the micro-tasks queue and run before any callbacks on the next tick of the event loop.

在下面的示例代码中,似乎获取并不会像Will和其他人所描述的那样将其解析处理程序功能简单地添加到微任务队列,因为正如Lewis所说,因为它需要网络活动,因此正在由网络任务源处理.但是,我不认为这是由于printHello阻塞"了网络任务,因为在下面的示例代码中,提取操作是在printHello之前触发的,并且网络响应也将在计时器完成之前发生.

From the sample code below, it appears fetch does not simply add it's resolve handler function to the micro-tasks queue as described by Will and others, because as Lewis stated since it requires network activity it is being handled by the Network Task Source. But, I don't believe this is due to printHello "blocking" the network task, because fetch is being fired prior to printHello in my sample code below, and the network response would occur before the timer completed as well.

如您在下面的示例中看到的那样,在收到获取响应(2000毫秒)后很长时间,我就延迟了将printHello添加到任务队列的时间,但是如果我们将代码执行的时间超过2000毫秒(因此仍在运行执行上下文),则将首先打印"Hello".这意味着fetch resolve()处理程序不会简单地添加到与其他promise处理程序一起触发的微任务队列中.

As you can see in the example below I have the printHello delayed to be added to the Task Queue long after the fetch response has been received (2000ms), yet if we block the code execution for longer than 2000ms (so that there is still running execution context) then "Hello" will be printed first. Meaning the fetch resolve() handler is NOT being simply added to the Micro-Task Queue where it would have fired along with the other promise handlers.

那么,如果在计时器任务完成之前(2000毫秒)接收到响应并理论上将其添加到任务队列中,为什么仍然在回调之后记录它?那么,我的猜测是计时器任务源必须比网络任务源具有更高的优先级.因此,两者都坐在他们的任务队列中,但是计时器任务队列在网络任务队列之前触发...

So, why is it still being logged after the callback if the response is received and theoretically added to the Task Queue prior to the timer task completing (at 2000ms)? Well, my guess is that the timer task source must be receiving priority over that of the network task source. And therefore both are sitting in their task queue, but the timer task queue is firing before the network task queue...

链接到规范:

计时器任务源- https ://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timer-task-source 联网任务源- https://html.spec.whatwg. org/multipage/webappapis.html#networking-task-source

Timer Task Source - https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timer-task-source Networking Task Source - https://html.spec.whatwg.org/multipage/webappapis.html#networking-task-source

function display(data){console.log("Fetch resolved!")}
function printHello(){console.log("Callback Time")}
function blockExecution() {
  console.log("Blocking execution...");
  alert('Wait at least 2000ms before closing');
}

const futureData = fetch('https://jsonplaceholder.typicode.com/todos/1');
futureData.then(response => response.json()).then(display);

setTimeout(printHello, 2000);

const p = new Promise(
    // this is called the "executor"
    (resolve, reject) => {
        console.log("I'm making a promise...");
        resolve("Promise resolved!");
        console.log("Promise is made...");
    }
);

p.then(
    // this is called the success handler
    result => console.log(result)
);

blockExecution();

console.log("Execution ended!");

这篇关于事件循环比回调队列更喜欢微任务队列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆