Понимание asyn c JS с обещаниями, задачами и очередью заданий - PullRequest
2 голосов
/ 05 августа 2020

Я изучал асинхронное c поведение в JS, и по большей части все шло хорошо. Я понимаю синхронный способ выполнения кода, единственный поток JS и то, как обратные вызовы, такие как внутри setTimeout, будут синхронизироваться API веб-браузера, а затем добавлены в очередь задач.

событие l oop будет постоянно проверять стек вызовов, и только когда он пуст (весь код syn c выполнен), он будет принимать функции, которые были поставлены в очередь в очереди задач. Отправляет их обратно в стек вызовов, и они выполняются.

Это довольно просто и является причиной того, что следующий код:

console.log('start');
setTimeout(() => console.log('timeout'), 0);
console.log('end');

будет выводить start, end, timeout.

Теперь, когда я начал читать об обещаниях, я понял, что они имеют более высокий приоритет, чем обычный асинхронный c код, такой как тайм-аут, интервал, прослушиватель событий, и вместо этого будут помещены в очередь заданий / очередь микрозадач. Событие l oop сначала установит приоритет этой очереди и выполнит все задания до исчерпания, прежде чем перейти к очереди задач.

Это все еще имеет смысл, и его можно увидеть, запустив:

console.log('start');
setTimeout(() => console.log('timeout'), 0);
Promise.resolve().then(() => console.log('promise'));
console.log('end');

Это выводит start, end, promise, timeout. Выполняется синхронный код, обратный вызов then помещается в стек из очереди микрозадач и выполняется, задача обратного вызова setTimeout из очереди задач отправляется и выполняется. Пока все хорошо.

Я могу осмыслить приведенный выше пример, в котором обещание выполняется немедленно и синхронно, как указано в официальной документации. То же самое произойдет, если мы создадим обещание с ключевым словом new и предоставим функцию исполнителя. Эта функция-исполнитель будет выполняться синхронно и разрешить функцию. Таким образом, когда встречается then, он может просто работать асинхронно на разрешенном обещании.

console.log('start');

const p1 = new Promise(resolve => {
    console.log('promise 1 log');
    resolve('promise 1');
});

p1.then(msg => console.log(msg));

console.log('end');

Приведенный выше фрагмент выведет start, promise 1 log, end, promise 1, доказывающее, что исполнитель работает синхронно.

И вот где я запутался с обещаниями, допустим, у нас есть следующий код:

console.log('start');

const p1 = new Promise(resolve => {
    console.log('promise 1 log');
    setTimeout(() => {
        resolve('promise 1');
    }, 0);
});

p1.then(msg => console.log(msg));

console.log('end');

Это приведет к start, promise 1 log, end, promise 1. Если функция исполнителя запускается сразу, это означает, что setTimeout внутри нее будет помещен в очередь задач для последующего выполнения. Насколько я понимаю, это означает, что обещание еще не выполнено. Мы переходим к методу then и обратному вызову внутри него. Он будет помещен в очередь заданий. остальная часть синхронного кода выполняется, и теперь у нас есть пустой стек вызовов.

Насколько я понимаю, обратный вызов обещания теперь будет иметь приоритет, но как он может выполняться с еще нерешенным обещанием? Обещание должно разрешиться только после того, как будет выполнен setTimeout внутри него, который все еще находится в очереди задач. Я слышал, без каких-либо дополнительных разъяснений, что тогда он будет работать только в том случае, если обещание будет выполнено, и из моего вывода я вижу, что это правда, но я не понимаю, как это будет работать в этом случае. Единственное, что я могу придумать, - это исключение или что-то подобное, и задача очереди задач получает приоритет перед микрозадачей.

Это оказалось долгим, поэтому я благодарен всем, кто нашел время, чтобы прочитать и ответить на это. Я хотел бы лучше понять очередь задач, очередь заданий и событие l oop, поэтому не стесняйтесь размещать подробный ответ! Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 05 августа 2020

Мы переходим к методу then и обратному вызову внутри него. Он будет помещен в очередь заданий.

Нет, при вызове then ничего не помещается в очередь заданий сразу, если обещание еще не выполнено. Обратный вызов будет установлен на обещание для выполнения позже, когда обещание будет выполнено, точно так же, как обработчик событий. Только когда вы вызываете resolve(), он фактически помещает его в очередь заданий.

Это работает так же, как setTimeout, где вы написали: « [] обратный вызов […] будет рассчитан по времени API веб-браузера и позже добавлено в очередь задач"- он не сразу ставит в очередь задачу, которая каким-то образом ждет, но ждет и затем ставит задачу в очередь для выполнения обратного вызова.

1 голос
/ 05 августа 2020

... обратный вызов обещания теперь будет иметь приоритет ...

Задачи в очереди микрозадач получают приоритет над задачами в очереди задач, только если они существуют.

В примере:

  • Микрозадача не ставится в очередь до тех пор, пока задача setTimout() не решит Обещание.
  • Задача и микрозадача не конкурируют. Они являются последовательными.
  • Задержки, налагаемые очередью задач и очередью микрозадач (в этом порядке), складываются.

... но как это может выполняться с неподвижным неразрешенное обещание?

Это не так. Обратный вызов .then() будет выполняться только после того, как обещание будет выполнено, и это выполнение зависит от задачи, помещенной в очередь задач setTimeout() (даже с нулевой задержкой).

...