- Notifications
You must be signed in to change notification settings - Fork179
Microtasks#223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Merged
Uh oh!
There was an error while loading.Please reload this page.
Merged
Microtasks#223
Changes fromall commits
Commits
Show all changes
2 commits Select commitHold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
94 changes: 47 additions & 47 deletions1-js/11-async/07-microtask-queue/article.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,112 @@ | ||
#Мікрозадачі | ||
Обробники промісів `.then`/`.catch`/`.finally`завжди асинхронні. | ||
Навіть коли проміс буде негайно виконано, код у рядках *нижче* `.then`/`.catch`/`.finally`все одно виконається до цих обробників. | ||
Ось демо: | ||
```js run | ||
let promise = Promise.resolve(); | ||
promise.then(() => alert("проміс виконано!")); | ||
alert("код виконано"); //цей alertпоказується першим | ||
``` | ||
Якщо ви його запустите, то побачите спочатку `код виконано`, а потім `проміс виконано!`. | ||
Це дивно, адже проміс, безумовно, виконується з самого початку. | ||
Чому потім спрацював `.then`? Що відбувається? | ||
##Черга мікрозадач | ||
Асинхронні задачі потребують належного керування. Для цього стандарт ECMAвизначає внутрішню чергу`PromiseJobs`,яку частіше називають "чергою мікрозадач" (термін v8). | ||
Як зазначено в [специфікації](https://tc39.github.io/ecma262/#sec-jobs-and-job-queues): | ||
-Черга функціонує за принципом першим-прийшов-першим-пішов: задачі, які стоять у черзі, виконуються першими. | ||
-Виконання задач починається лише тоді, коли більше нічого не виконується. | ||
Або, простіше кажучи, коли проміс виконано, його обробники`.then/catch/finally`поміщаються в чергу; вони ще не виконані. Коли рушій JavaScriptзвільняється від виконання поточного коду, він бере задачу з черги та виконує її. | ||
Ось чому "код виконано" у прикладі вище показується першим. | ||
 | ||
Обробники промісів завжди проходять через цю внутрішню чергу. | ||
Якщо є ланцюжок з кількох`.then/catch/finally`,то кожен з них виконується асинхронно. Тобто спочатку він потрапляє в чергу, а потім виконується, коли виконання поточного коду буде завершено, а попередні обробники в черзі виконані. | ||
**Що робити, якщо порядок має значення для нас? Як ми можемо зробити так, щоб `код виконано` відображалося після `проміс виконано`?** | ||
Легко, просто поставте його в чергу за допомогою `.then`: | ||
```js run | ||
Promise.resolve() | ||
.then(() => alert("проміс виконано!")) | ||
.then(() => alert("код виконано")); | ||
``` | ||
Тепер порядок відповідає задуму. | ||
##Необроблені помилки | ||
Пам’ятаєте подію `unhandledrejection`зі статті <info:promise-error-handling>? | ||
Тепер ми бачимо, як самеJavaScriptдізнається про необроблені помилки. | ||
**"Необроблена помилка" виникає тоді, коли помилка проміса не обробляється в кінці черги мікрозадач.** | ||
Зазвичай, якщо ми очікуємо помилку, то додаємо `.catch`до ланцюжка промісів для її обробки: | ||
```js run | ||
let promise = Promise.reject(new Error("Помилка в промісі!")); | ||
*!* | ||
promise.catch(err => alert('спіймана')); | ||
*/!* | ||
//не запуститься: помилка оброблена | ||
window.addEventListener('unhandledrejection', event => alert(event.reason)); | ||
``` | ||
Але якщо ми забудемо додати`.catch`,тоді, коли черга мікрозадач буде порожня, рушій ініціює подію: | ||
```js run | ||
let promise = Promise.reject(new Error("Помилка в промісі!")); | ||
//Помилка в промісі! | ||
window.addEventListener('unhandledrejection', event => alert(event.reason)); | ||
``` | ||
А що, якщо ми обробимо помилку пізніше? Наприклад ось так: | ||
```js run | ||
let promise = Promise.reject(new Error("Помилка в промісі!")); | ||
*!* | ||
setTimeout(() => promise.catch(err => alert('спіймана')), 1000); | ||
*/!* | ||
// Error:Помилка в промісі! | ||
window.addEventListener('unhandledrejection', event => alert(event.reason)); | ||
``` | ||
Тепер, якщо ми його запустимо, то спочатку побачимо `Помилка в промісі!`, а потім `спіймана`. | ||
Якби ми не знали про чергу мікрозадач, то могли б задатися питанням: "Чому запустився обробник`unhandledrejection`? Ми спіймали та обробили помилку!" | ||
Але тепер ми розуміємо, що `unhandledrejection`генерується, коли черга мікрозадач завершується: рушій перевіряє проміси, і, якщо будь-який з них знаходиться в стані "rejected", то ініціюється ця подія. | ||
У вищенаведеному прикладі`.catch`, доданий в `setTimeout`, також спрацює. Але це відбувається пізніше, після того, як `unhandledrejection`вже виникло, тому це ні на що не впливає. | ||
##Підсумки | ||
Обробка промісів завжди асинхронна, оскільки всі дії промісів проходять через внутрішню чергу "promise jobs", яку також називають "чергою мікрозадач" (термін v8). | ||
Тому обробники`.then/catch/finally`завжди викликаються після виконання поточного коду. | ||
Якщо нам потрібно гарантувати, що фрагмент коду виконується після`.then/catch/finally`,ми можемо додати його до ланцюжкового виклику `.then`. | ||
У більшості рушіїв Javascript, включаючи браузери та Node.js,концепція мікрозадач тісно пов’язана з "циклом подій" ("event loop") і "макрозадачами".Оскільки вони не мають прямого відношення до промісів, вони розглянуті в іншій частині підручника, у статті <info:event-loop>. |
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.