Начиная с promise, process.nextTick и setTimeout, поговорим об очереди заданий (очереди задач) в цикле событий.

Краткое введение: рассказ о порядке выполнения promise.resove, setTimeout, setImmediate, process.nextTick в очереди EvenLoop

1. Введение проблемы

цикл событий: обращается к основному потоку для чтения задач из «очереди задач» в цикле

// 例1:

setTimeout(function(){console.log(1)},0);

console.log(2)

//输出2,1

В приведенном выше примере мы понимаем, что сначала выполняется задача синхронизации в основном потоке, а затем задача считывается из цикла событий после выполнения задачи основного потока, поэтому сначала выведите 2, а затем выведите 1.

Порядок, в котором цикл обработки событий считывает задачи, зависит от ограничений различных правил чтения задач в очереди заданий. Например, следующий пример

// 例2:

setTimeout(function () {
  console.log(3);
}, 0);

Promise.resolve().then(function () {
  console.log(2);
});
console.log(1);
//输出为  1  2 3

Первый вывод 1, без проблем, потому что задача синхронизации выполняется первой в основном потоке, проблема здесь в том, как определить приоритет выполнения задач setTimeout и Promise.then.

2. Порядок выполнения в очереди заданий

Очереди в Job queue делятся на два типа: macro-task (макрозадача) и microTask (микрозадача).

Предположим, что
очередь макро-задач (макрозадач) содержит задачи:  а1, а2, а3

Очередь микрозадач содержит задачи:  b1, b2, b3

Порядок выполнения следующий: сначала выполнить задачу в начале очереди марко-задач, то есть  задачу а1  , после выполнения выполнить все задачи в очереди микрозадач, то есть выполнить b1, b2, b3 в последовательность, и очистить микрозадачу после выполнения.задача в задаче, затем выполнить вторую задачу в марко-задаче, и цикл по очереди

Поняв порядок выполнения очередей макрозадач и микрозадач, давайте посмотрим на задачи, фактически содержащиеся в этих двух типах очередей в реальных сценариях (в качестве примера возьмем движок узла V8), в узле V8 реальный порядок задач для этих двух типов следующий

Очередь макро-задачи (macro-задачи) на самом деле содержит задачи:

script (основной программный код), setTimeout, setInterval, setImmediate, I/O (передача данных), рендеринг пользовательского интерфейса (рендеринг DOM)

Очередь микрозадач (микрозадач) на самом деле содержит задачи:

process.nextTick, Promises, MutationObserver (мониторинг дерева DOM)

Отсюда получаем порядок выполнения должен быть:

скрипт (основной программный код)—>process.nextTick—>Promises—>MutationObserver—>setTimeout—>setInterval—>setImmediate—>I/O—>рендеринг пользовательского интерфейса

В ES6 очередь макрозадач (макро) также называется ScriptJobs, а микрозадача (микро) также называется PromiseJobs.

3. Пример последовательности выполнения в реальной среде

(1) setTimeout и обещание

例3:

setTimeout(function () {
  console.log(3);
}, 0);

Promise.resolve().then(function () {
  console.log(2);
});

console.log(1);

Давайте сначала возьмем пример в Разделе 1 в качестве примера, и последовательность, которой нужно следовать здесь, такова:

script (основной программный код) ——>promise——>setTimeout
соответствует выводу по очереди: 1 ——>2————>3

(2) process.nextTick, обещание, setTimeout

例子4:
setTimeout(function(){console.log(1)},0);

new Promise(function(resolve,reject){
   console.log(2);
   resolve();
}).then(function(){console.log(3)
}).then(function(){console.log(4)});

process.nextTick(function(){console.log(5)});

console.log(6);
//输出2,6,5,3,4,1

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

Сначала проанализируйте порядок выполнения очереди заданий (очереди задач):

скрипт (основной программный код) --> process.nextTick --> обещание --> setTimeout

1.)  Основная часть : Строительная часть обещания определения является синхронной,
поэтому сначала выведите 2, а затем выведите 6 в основной части (в случае синхронизации строго в соответствии с порядком определения)

2.) process.nextTick : вывод 5

3.) promise : часть обещания здесь, строго говоря, на самом деле является частью обещания.затем, а вывод равен 3,4.

4.)  setTimeout  : вывод 1 в конце

Полная последовательность выполнения: 2—>6—>5—>3—>4—>1

(3) Более сложный пример

setTimeout(function(){console.log(1)},0);

new Promise(function(resolve,reject){
   console.log(2);
   setTimeout(function(){resolve()},0)
}).then(function(){console.log(3)
}).then(function(){console.log(4)});

process.nextTick(function(){console.log(5)});

console.log(6);

//输出的是  2 6 5 1 3 4

Отличие этой ситуации от нашего примера в (2) заключается в том, что при построении промиса нет синхронного разрешения , поэтому promise.then не существует в текущей очереди выполнения, только когда обещание переводится из pending в Resolve. then, и это решение завершается за время setTimout, поэтому в итоге выводятся 3,4.

おすすめ

転載: blog.csdn.net/weixin_52615140/article/details/128250391