оригинал:Джейк Арчибальд.com/2015/tasks-…
Переводчик: Front-end Xiaozhi
Ставь лайк и смотри, поиск в WeChat【Переезд в мир】Обратите внимание на этого человека, который не имеет большого фабричного прошлого, но имеет восходящий и позитивный настрой. эта статья
GitHub
GitHub.com/QQ449245884…Он был включен, статьи были классифицированы, и многие мои документы и учебные материалы были систематизированы.
Все говорили, что нет проекта для написания резюме, поэтому я помог вам найти проект, и это было с бонусом.【Учебник по строительству】.
Рассмотрим следующий код JavaScript:
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
Каков порядок печати консоли?
Отвечать
Правильный ответ:script start
, script end
, promise1
, promise2
, setTimeout
, но результаты противоречивы из-за поддержки различных браузеров.
Microsoft Edge, Firefox 40, iOS Safari и Desktop Safari 8.0.8 Печатьpromise1
а такжеpromise2
До сначала будет печатьsetTimeout
- Похоже, производители браузеров различаются. Это действительно странно, потому что Firefox 39 и Safari 8.0.7 всегда корректны.
почему это
Чтобы понять это, нужно понять, как цикл обработки событий обрабатывает задачи и микрозадачи.
Каждая "ниточка" имеет своюцикл событий, поэтому каждый веб-воркер имеет свой собственный цикл событий и, следовательно, может выполняться независимо, в то время как все окна из одного домена совместно используют цикл событий, чтобы они могли обмениваться данными синхронно.
Цикл событий продолжает работать до тех пор, пока очередь задач не будет очищена от задач. Цикл событий имеет несколько источников задач, которые гарантируют порядок выполнения внутри этого источника (например, IndexedDB определяет свою собственную спецификацию), но браузер может выбирать, какой источник выполнять задачи в каждом цикле. Это позволяет браузерам расставлять приоритеты для задач, чувствительных к производительности, таких как пользовательский ввод и т. д.
TasksВ источнике задачи этот браузер может войти в домен JavaScript/DOM изнутри и убедиться, что эти операции в порядке. Во время выполнения ЗАДАЧ браузер может обновить рендеринг. Это также относится к задаче от щелчка мыши до обратного вызова события.
setTimeout
задержать на заданное время, а затем запланировать новую задачу для ее обратного вызова. поэтомуsetTimeout
печатьscript end
после печати, потому что печатьscript end
является частью первой задачи, аsetTimeout
в отдельной задаче.
**Микрозадачи** обычно планируются для действий, которые должны произойти сразу после выполнения текущего скрипта, например, ответ на пакет операций или выполнение асинхронной обработки, не влияющей на всю новую задачу.
Пока в середине выполнения и в конце каждой задачи нет другого JavaScript, очередь микрозадач обрабатывается после обратного вызова. Любые другие микрозадачи, поставленные в очередь во время микрозадачи, добавляются в конец очереди и обрабатываются. Микрозадачи включают обратные вызовы MutationObserver. Например, в приведенном выше примереpromise
изcallback
.
Одинsettled
Обещание государства или сталоsettled
состояние (асинхронный запрос урегулирован) обещание, оно будет немедленноcallback(then)
Поместите его в очередь микрозадач.
Это гарантируетpromise
Обратные вызовы являются асинхронными, даже еслиpromise
сталsettled
условие. Поэтомуsettled
изpromise
передача.then(yey,nay)
немедленно добавит микрозадачу в очередь микрозадач.
поэтомуpromise1
а такжеpromise2
Будет вscript end
после печати, потому что работающий в данный момент скрипт должен завершиться перед обработкой микрозадачи.promise1
а такжеpromise2
существуетsetTimeout
печатать раньше, потому что микрозадачи всегда выполняются до следующей.
ОК, запустите его шаг за шагом:
В чем будет разница между браузерами?
Порядок, в котором печатают некоторые браузеры,script start, script end, setTimeout, promise1, promise2
. они вsetTimeout
бежать заpromise
Перезвоните. Звонят скорее всегоpromise
Обратный вызов выполняется как часть новой задачи, а не как микрозадача.
Это также понятно, потому чтоpromise
Из ECMAScript вместо HTML. ECMAScript имеет "Операция"концепция похожа на микрозадачи, но отношения не ясны за пределами расплывчатых обсуждений в списке рассылки. Однако общий консенсус заключается в том, чтоpromise
Должен быть частью очереди микрозадач и не зря.
Будуpromise
Обработка как задачи может привести к проблемам с производительностью, поскольку обратные вызовы не обязательно нужно откладывать для вещей, связанных с задачей (например, рендеринга). Это также вызывает недетерминизм из-за взаимодействия с другими источниками задач и может нарушить взаимодействие с другими API, подробнее об этом позже.
Вот обратная связь по краюэто неправильноpromises
как задача. WebKit nightly сделал это правильно, поэтому я думаю, что Safari в конечном итоге исправит это, и в Firefox 43, похоже, это есть.
Как узнать, использует ли что-то задачи или микрозадачи
Попробовать это - один из способов увидеть относительноpromise
а такжеsetTimeout
Как печатать, хотя это зависит от правильной реализации.
Один из способов — посмотреть спецификацию: поставить задачу в очередь:step 14 of setTimeout
Добавьте микрозадачу в очередь:step 5 of queuing a mutation record
Как упоминалось выше, ECMAScript называет микрозадачи заданиями: вызовите EnqueueJob, чтобы поставить микрозадачу в очередь:step 8.a of PerformPromiseThen
Дагуай уровня босса
Вот кусок html-кода:
<div class="outer">
<div class="inner"></div>
</div>
Дайте код JS ниже, если вы нажметеdiv.inner
Что вы будете печатать?
// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');
// Let's listen for attribute changes on the
// outer element
new MutationObserver(function() {
console.log('mutate');
}).observe(outer, {
attributes: true
});
// Here's a click listener…
function onClick() {
console.log('click');
setTimeout(function() {
console.log('timeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise');
});
outer.setAttribute('data-random', Math.random());
}
// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);
Попробуйте, прежде чем искать ответ
попробуй
Отличается ли он от того, что вы ожидали? Если это так, результат, который вы получите, вероятно, также будет правильным. К сожалению, реализации браузеров неоднородны, вот результаты тестов для каждого браузера:
кто прав?
Расписание'click
«Событие — это задача. Наблюдатель мутаций и обратные вызовы обещаний перечислены как микрозадачи.setTimeout
Обратный вызов указан как задача. Таким образом, процесс запуска выглядит следующим образом:
Так что Хром прав. Что нового для меня, так это то, что микрозадачи запускаются после обратных вызовов (пока не запущен никакой другой Javascript), я думал, что это может быть выполнено только в конце задачи.
Что не так с браузером?
Для мутационных обратных вызовов как Firefox, так и Safari правильно завершают события щелчка внутренней и внешней областей, очищая очередь микрозадач, ноpromises
Обработка очереди выглядит иchrome
Разные. Это несколько простительно, так как связь между заданиями и микрозадачами не ясна, но я все же ожидаю обработки между обратными вызовами событий.Firefox ticket. Safari ticket.
Для Edge мы видели это неправильноpromises
В качестве задачи он не устанавливает очередь MicroTask между Click Callbacks, но после того, как выполняются обратные вызовы кликов, поэтому в общей сложности только одинmutate
в двоемclick
распечатать потом.
Улучшение босса 1-го уровня для битвы с монстром
Все еще используя приведенный выше пример, что, если мы запустим следующий код:
inner.click();
Как и прежде, он сработаетclick
событие, но на этот раз оно вызывается через JS.
попробуй
Вот как работает каждый браузер:
Клянусь, я продолжаю получать разные результаты от Chrome, я обновлял эту диаграмму столько раз, что думал, что неправильно тестировал Canary. Если вы получаете другие результаты в Chrome, сообщите мне, какая версия в комментариях.
Почему это не так?
Это должно выглядеть так:
Таким образом, правильный порядок: щелчок, щелчок, обещание, изменение, обещание, тайм-аут, тайм-аут, кажется, Chrome прав.
Ранее это означало, что микрозазки бежали между обратными вызовами слушателя, но.click()
приведет к тому, что событие будет отправлено синхронно, поэтому вызов.click()
Сценарий все еще находится в стеке между обратными вызовами. Приведенные выше правила гарантируют, что микрозадачи не прерывают выполнение JavaScript в середине. Это означает, что мы не обрабатываем очередь микрозадач между обратными вызовами слушателя, они обрабатываются после двух слушателей.
Суммировать
Задачи выполняются последовательно, и браузер может отображать между ними:
Микрозадачи выполняются последовательно, и выполняются:
-
После каждого обратного вызова, пока не выполняется никакой другой код.
-
в конце каждого задания.
Ошибки, которые могут существовать после развертывания кода, не могут быть известны в режиме реального времени.Чтобы решить эти ошибки впоследствии, много времени тратится на отладку журнала.Кстати, я рекомендую всем полезный инструмент мониторинга ошибок.Fundebug.
общаться с
Статья постоянно обновляется каждую неделю. Вы можете выполнить поиск «Big Move to the World» в WeChat, чтобы прочитать и обновить ее как можно скорее (на одну или две статьи раньше, чем в блоге). Эта статья находится на GitHub.GitHub.com/QQ449245884…Он был включен, и многие мои документы были разобраны. Добро пожаловать в Звезду и совершенство. Вы можете обратиться в тестовый центр для ознакомления во время собеседования. Кроме того, обратите внимание на паблик-аккаунт и ответьте в фоновом режиме.Благосостояние, вы можете увидеть преимущества, вы знаете.