Цикл событий предпочитает очередь микрозадач по очереди обратного вызова? - PullRequest
0 голосов
/ 08 июня 2018

Я тестировал концепции асинхронного кода в JS.Запутался между очередью обратного вызова и порядком очереди микрозадач.Всякий раз, когда объекты обещания разрешаются, метод выполнения {then} помещается в очередь микрозадач, в то время как обратные вызовы функций таймера браузера, таких как setTimeout, помещаются в очередь обратных вызовов.Цикл обработки событий непрерывно проверяет очередь и помещает функции из очереди в стек вызовов всякий раз, когда стек вызовов становится пустым.Цикл обработки событий должен отдавать предпочтение очереди микрозадач по сравнению с обычной очередью обратного вызова, но в примере: https://jsfiddle.net/BHUPENDRA1011/2n89ftmp/ происходит иначе.

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 !')

ожидаемый результат

  • Я первый!
  • Привет, вернись из выборки
  • привет

фактический вывод:

  • Я первый!
  • Привет
  • Привет, вернись, принеси

Пожалуйста, дайте мне знать, как это происходит здесь.

Спасибо

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Я думаю, что проблема в том, что ваша функция blockfor300ms не блокирует поток достаточно долго, чтобы выборка получила ответ.В очереди заданий ничего не будет (пока), когда цикл обработки событий увидит, что он может вызвать printHello.

0 голосов
/ 08 июня 2018

futureData на самом деле является обещанием получения, поэтому при вызове fetch в очередь задач ставится сетевая задача.В результате, printHello обязательно будет выполнено перед сетевой задачей, поскольку они обе задачи.И метод display будет помещен в очередь микрозадач только тогда, когда обещание сетевой задачи будет выполнено.Микрозадачи по определению выполняются только в конце каждой задачи.Так что display будет вызываться в конце сетевой задачи, когда printHello уже был вызван задолго до этого.

Если вы хотите, чтобы display вызывался до printHello, futureData должентолько очереди микрозадач.Давайте немного изменим ваш пример.

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

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

let now = Date.now();
function executeFutureDataWithMicrotasksOnly() {
    // Execute microtasks continually in 300ms.
    return Promise.resolve().then(() => Date.now() - now < 300 && executeFutureDataWithMicrotasksOnly());
}

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 = executeFutureDataWithMicrotasksOnly();
// 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 !')

Как видно из приведенного выше примера, если вы замените fetch на метод, имеющий только микрозадачи, порядок выполнения изменится, как и ожидалось, как для fetch, так и дляexecuteFutureDataWithMicrotasksOnly выполняются за аналогичный промежуток времени.Когда futureData больше не ставит задачи в очередь, все микрозадачи, включая display, будут выполнены в конце текущей выполняемой задачи, которая является предыдущей задачей задачи printHello.

...