From 63b25a60ceb2d2ae090d2113295065d374c110d5 Mon Sep 17 00:00:00 2001 From: georgyna Date: Wed, 5 Jul 2023 20:51:35 +0300 Subject: [PATCH 1/5] Add first use-case translation --- 2-ui/99-ui-misc/03-event-loop/article.md | 112 +++++++++++------------ images.yml | 14 +++ 2 files changed, 70 insertions(+), 56 deletions(-) diff --git a/2-ui/99-ui-misc/03-event-loop/article.md b/2-ui/99-ui-misc/03-event-loop/article.md index 3ea0c2c57..99b73d1c4 100644 --- a/2-ui/99-ui-misc/03-event-loop/article.md +++ b/2-ui/99-ui-misc/03-event-loop/article.md @@ -1,64 +1,64 @@ -# Event loop: microtasks and macrotasks +# Цикл подій: мікрозавдання та макрозавдання -Browser JavaScript execution flow, as well as in Node.js, is based on an *event loop*. +Потік виконання JavaScript в браузері, так само як і в Node.js, базується на *циклі подій*. -Understanding how event loop works is important for optimizations, and sometimes for the right architecture. +Розуміння принципу роботи циклу подій важливе для оптимізації, та іноді для правильної архітектури. -In this chapter we first cover theoretical details about how things work, and then see practical applications of that knowledge. +В цьому розділі ми спочатку розглянемо теоретичну базу, а потім практичне застосування цих знань. -## Event Loop +## Цикл подій -The *event loop* concept is very simple. There's an endless loop, where the JavaScript engine waits for tasks, executes them and then sleeps, waiting for more tasks. +Концепція *циклу подій* дуже проста. Існує нескінченний цикл, в якому рушій JavaScript очікує завдання, виконує їх, а потім переходить в режим очікування нових завдань. -The general algorithm of the engine: +Загальний алгоритм рушія: -1. While there are tasks: - - execute them, starting with the oldest task. -2. Sleep until a task appears, then go to 1. +1. Поки є завдання: + - виконати їх, починаючи з найстарішого. +2. Очікувати поки завдання не з'явиться, потім перейти до пункту 1. -That's a formalization for what we see when browsing a page. The JavaScript engine does nothing most of the time, it only runs if a script/handler/event activates. +Це формалізація того, що ми бачимо, гортаючи веб-сторінку. Рушій JavaScript більшість часу не робить нічого, він працює лише коли спрацьовує скрипт, обробник подій чи подія. -Examples of tasks: +Приклади завдань: -- When an external script ` ``` -...But we also may want to show something during the task, e.g. a progress bar. +...Але можливо ми хочемо показати щось під час виконання завдання, наприклад індикатор прогресу. -If we split the heavy task into pieces using `setTimeout`, then changes are painted out in-between them. +Якщо ми розділимо велике завдання на частини використовуючи `setTimeout`, тоді зміни будуть відмальовані в проміжках між частинами. -This looks prettier: +Це вже виглядає краще: ```html run
@@ -197,7 +197,7 @@ This looks prettier: function count() { - // do a piece of the heavy job (*) + // зробити шматочок важкої роботи (*) do { i++; progress.innerHTML = i; @@ -213,40 +213,40 @@ This looks prettier: ``` -Now the `
` shows increasing values of `i`, a kind of a progress bar. +Тепер `
` показує `i`, яке поступово збільшується, щось схоже на індикатор прогресу. -## Use case 3: doing something after the event +## Приклад 3: виконання чогось після події -In an event handler we may decide to postpone some actions until the event bubbled up and was handled on all levels. We can do that by wrapping the code in zero delay `setTimeout`. +В обробнику подій ми можемо вирішити відкласти певні дії поки подія не вспливе і не буде оброблена на всіх рівнях. Ми можемо зробити це огорнувши код в `setTimeout` з нульовою затримкою. -In the chapter we saw an example: custom event `menu-open` is dispatched in `setTimeout`, so that it happens after the "click" event is fully handled. +В розділі ми бачили приклад: кастомна подія `menu-open` генерується через `setTimeout` для того, щоб виконатись після того як подія "click" буде повністю оброблена. ```js menu.onclick = function() { // ... - // create a custom event with the clicked menu item data + // створюємо кастомну подію з даними клікнутого пункту меню let customEvent = new CustomEvent("menu-open", { bubbles: true }); - // dispatch the custom event asynchronously + // асинхронно згенерувати кастомну подію setTimeout(() => menu.dispatchEvent(customEvent)); }; ``` -## Macrotasks and Microtasks +## Макрозавдання та Мікрозавдання -Along with *macrotasks*, described in this chapter, there are *microtasks*, mentioned in the chapter . +Разом з *макрозавданнями*, описаними в цьому розділі, існують *мікрозавдання*, описані в розділі . -Microtasks come solely from our code. They are usually created by promises: an execution of `.then/catch/finally` handler becomes a microtask. Microtasks are used "under the cover" of `await` as well, as it's another form of promise handling. +Мікрозавдання приходять лише з нашого коду. Їх зазвичай створюють проміси: виконання обробника `.then/catch/finally` стає мікрозавданням. Мікрозавдання також використовуються "під капотом" `await`, так як це форма обробки проміса. -There's also a special function `queueMicrotask(func)` that queues `func` for execution in the microtask queue. +Також існує спеціальна функція `queueMicrotask(func)`, яка ставить `func` в чергу мікрозавдань. -**Immediately after every *macrotask*, the engine executes all tasks from *microtask* queue, prior to running any other macrotasks or rendering or anything else.** +**Одразу після кожного *макрозавдання*, рушій виконує всі завдання з черги *мікрозавдань* перед тим як виконати якесь макрозавдання чи рендеринг чи виконати щось іще.** -For instance, take a look: +Наприклад, подивіться: ```js run setTimeout(() => alert("timeout")); @@ -257,23 +257,23 @@ Promise.resolve() alert("code"); ``` -What's going to be the order here? +Який тут буде порядок виконання? -1. `code` shows first, because it's a regular synchronous call. -2. `promise` shows second, because `.then` passes through the microtask queue, and runs after the current code. -3. `timeout` shows last, because it's a macrotask. +1. `code` покажеться першим, тому що це звичайний синхронний виклик. +2. `promise` покажеться другим, тому що `.then` проходить через чергу мікрозадач, і виконується після поточного синхронного коду. +3. `timeout` покажеться останнім, тому що це макрозавдання. -The richer event loop picture looks like this (order is from top to bottom, that is: the script first, then microtasks, rendering and so on): +Більш детальна ілюстрація циклу подій виглядає так (порядок з верху до низу: спочатку script, потім мікрозавдання, рендеринг і так далі): ![](eventLoop-full.svg) -All microtasks are completed before any other event handling or rendering or any other macrotask takes place. +Всі мікрозавдання завершуються до обробки будь-яких подій чи рендерингу чи виконання інших макрозавдань. -That's important, as it guarantees that the application environment is basically the same (no mouse coordinate changes, no new network data, etc) between microtasks. +Це важливо, тому що це гарантує, що середовище застосунку залишається незмінним між мікрозадачами (не змінились координати мишки, не з’явились нові дані через мережу тощо). -If we'd like to execute a function asynchronously (after the current code), but before changes are rendered or new events handled, we can schedule it with `queueMicrotask`. +Якщо ми хочемо виконати функцію асинхронно (після поточного коду), але до відображення змін чи обробки нових подій, ми можемо запланувати її за допомогою `queueMicrotask`. -Here's an example with "counting progress bar", similar to the one shown previously, but `queueMicrotask` is used instead of `setTimeout`. You can see that it renders at the very end. Just like the synchronous code: +Наступний приклад показує індикатор прогресу, схожий на попередній, але `queueMicrotask` використовується замість `setTimeout`. Зауважте, що відмалювання відбувається лише в самому кінці. Так як і з синхронним кодом: ```html run
@@ -283,7 +283,7 @@ Here's an example with "counting progress bar", similar to the one shown previou function count() { - // do a piece of the heavy job (*) + // зробити частину великого завдання (*) do { i++; progress.innerHTML = i; @@ -301,39 +301,39 @@ Here's an example with "counting progress bar", similar to the one shown previou ``` -## Summary +## Підсумок -A more detailed event loop algorithm (though still simplified compared to the [specification](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)): +Більш детальний алгоритм циклу подій (хоч і спрощений порівняно зі [специфікацією](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)): -1. Dequeue and run the oldest task from the *macrotask* queue (e.g. "script"). -2. Execute all *microtasks*: - - While the microtask queue is not empty: - - Dequeue and run the oldest microtask. -3. Render changes if any. -4. If the macrotask queue is empty, wait till a macrotask appears. -5. Go to step 1. +1. Обрати і виконати найстаріше завдання з черги *макрозавдань* (наприклад, "script"). +2. Виконати всі *мікрозавдання*: + - Поки черга мікрозавдань не пуста: + - Обрати з черги і виконати найстаріше мікрозавдання. +3. Відмалювати зміни, якщо вони є. +4. Якщо черга макрозавдань пуста, зачекати поки макрозавдання з’явиться. +5. Перейти до кроку 1. -To schedule a new *macrotask*: -- Use zero delayed `setTimeout(f)`. +Щоб додати в чергу нове *макрозавдання*: +- Використайте `setTimeout(f)` з нульовою затримкою. -That may be used to split a big calculation-heavy task into pieces, for the browser to be able to react to user events and show progress between them. +Цей спосіб можна використати для розбиття великого важкообчислюваного завдання на частини, щоб браузер мав змогу реагувати на користувацькі події і показувати індикатор прогресу між ними. -Also, used in event handlers to schedule an action after the event is fully handled (bubbling done). +Також це використовується в обробниках подій, щоб відкласти дію до моменту повної обробки події (вспливання завершене). -To schedule a new *microtask* -- Use `queueMicrotask(f)`. -- Also promise handlers go through the microtask queue. +Щоб запланувати нове *мікрозавдання* +- Використайте `queueMicrotask(f)`. +- Також обробники промісів виконуються в черзі мікрозавдань. -There's no UI or network event handling between microtasks: they run immediately one after another. +Жодні UI або мережеві події не обробляються між мікрозавданнями: мікрозавдання виконуються негайно один за одним. -So one may want to `queueMicrotask` to execute a function asynchronously, but within the environment state. +Тому `queueMicrotask` можна використати для асинхронного виконання фунції, але в одному й тому ж стані середовища. ```smart header="Web Workers" -For long heavy calculations that shouldn't block the event loop, we can use [Web Workers](https://html.spec.whatwg.org/multipage/workers.html). +Для довгих важких обчислень, які не повинні блокувати цикл подій, ми можемо використати [Web Workers](https://html.spec.whatwg.org/multipage/workers.html). -That's a way to run code in another, parallel thread. +Це спосіб запустити код в іншому, паралельному потоці. -Web Workers can exchange messages with the main process, but they have their own variables, and their own event loop. +Web Workers можуть обмінюватись повідомленнями з основним процесом, але вони мають власні змінні і власний цикл подій. -Web Workers do not have access to DOM, so they are useful, mainly, for calculations, to use multiple CPU cores simultaneously. +Web Workers не мають доступу до DOM, тож вони корисні переважно для обчислень. Вони можуть використовувати декілька ядер процесора одночасно. ``` diff --git a/images.yml b/images.yml index e453c6aa7..d4c458a21 100644 --- a/images.yml +++ b/images.yml @@ -162,4 +162,18 @@ eventLoop.svg: "queue": text: "макрозавдань" position: "left" + +# 2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg + +eventLoop-full.svg: + "event": + text: "цикл" + position: "center" + "loop": + text: "подій" + position: "center" + "microtasks": + text: "мікрозавдання" + "render": + text: "рендеринг" From 4e81fd5a1997ecd95cf8eeaee6d3965155cbf928 Mon Sep 17 00:00:00 2001 From: georgyna Date: Thu, 6 Jul 2023 12:48:56 +0300 Subject: [PATCH 3/5] Translate pictures --- .../03-event-loop/eventLoop-full.svg | 2 +- 2-ui/99-ui-misc/03-event-loop/eventLoop.svg | 2 +- images.yml | 29 ------------------- 3 files changed, 2 insertions(+), 31 deletions(-) diff --git a/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg b/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg index 593cbab9b..ca9aeaf60 100644 --- a/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg +++ b/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg @@ -1 +1 @@ -...mousemoveevent looprendermicrotasksrendermicrotasksscriptsetTimeout \ No newline at end of file +...mousemoveцикл подійрендерингмікрозавданнярендерингмікрозавданняscriptsetTimeout \ No newline at end of file diff --git a/2-ui/99-ui-misc/03-event-loop/eventLoop.svg b/2-ui/99-ui-misc/03-event-loop/eventLoop.svg index 6dc459ef8..1d54ac083 100644 --- a/2-ui/99-ui-misc/03-event-loop/eventLoop.svg +++ b/2-ui/99-ui-misc/03-event-loop/eventLoop.svg @@ -1 +1 @@ -...mousemovescriptevent loopmacrotask queuesetTimeout \ No newline at end of file +...mousemovescriptцикл подійчерга макрозавданьsetTimeout \ No newline at end of file diff --git a/images.yml b/images.yml index d4c458a21..bfb400bfb 100644 --- a/images.yml +++ b/images.yml @@ -148,32 +148,3 @@ demo.svg: before-prepend-append-after.svg: (…nodes-or-strings): "(...вузли або рядки)" -# 2-ui/99-ui-misc/03-event-loop/eventLoop.svg -eventLoop.svg: - "event": - text: "цикл" - position: "center" - "loop": - text: "подій" - position: "center" - "macrotask": - text: "черга" - position: "left" - "queue": - text: "макрозавдань" - position: "left" - -# 2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg - -eventLoop-full.svg: - "event": - text: "цикл" - position: "center" - "loop": - text: "подій" - position: "center" - "microtasks": - text: "мікрозавдання" - "render": - text: "рендеринг" - From c09db9a7f688093fa242d503e6f6ad5494ca92ab Mon Sep 17 00:00:00 2001 From: georgyna Date: Thu, 6 Jul 2023 12:51:48 +0300 Subject: [PATCH 4/5] Remove extra space --- images.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/images.yml b/images.yml index bfb400bfb..67f89b51f 100644 --- a/images.yml +++ b/images.yml @@ -148,3 +148,4 @@ demo.svg: before-prepend-append-after.svg: (…nodes-or-strings): "(...вузли або рядки)" + From 58aee72d3d7429157199f9da61c50b1d9d8ab007 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sun, 16 Jul 2023 17:37:08 +0300 Subject: [PATCH 5/5] Apply suggestions from code review --- 2-ui/99-ui-misc/03-event-loop/article.md | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/2-ui/99-ui-misc/03-event-loop/article.md b/2-ui/99-ui-misc/03-event-loop/article.md index e81fdcb9e..3b0d686a9 100644 --- a/2-ui/99-ui-misc/03-event-loop/article.md +++ b/2-ui/99-ui-misc/03-event-loop/article.md @@ -1,13 +1,13 @@ -# Цикл подій: мікрозавдання та макрозавдання +# Цикл подій (event loop): мікрозавдання (microtasks) та макрозавдання (macrotasks) -Потік виконання JavaScript в браузері, так само як і в Node.js, базується на *циклі подій*. +Потік виконання JavaScript в браузері, так само як і в Node.js, базується на *циклі подій (event loop)*. Розуміння принципу роботи циклу подій важливе для оптимізації, та іноді для правильної архітектури. В цьому розділі ми спочатку розглянемо теоретичну базу, а потім практичне застосування цих знань. -## Цикл подій +## Цикл подій (event loop) Концепція *циклу подій* дуже проста. Існує нескінченний цикл, в якому рушій JavaScript очікує завдання, виконує їх, а потім переходить в режим очікування нових завдань. @@ -17,7 +17,7 @@ - виконати їх, починаючи з найстарішого. 2. Очікувати поки завдання не з’явиться, потім перейти до пункту 1. -Це формалізація того, що ми бачимо, гортаючи веб-сторінку. Рушій JavaScript більшість часу не робить нічого, він працює лише коли спрацьовує скрипт, обробник подій чи подія. +Це формалізація того, що ми бачимо, гортаючи вебсторінку. Рушій JavaScript більшість часу не робить нічого, він працює лише коли спрацьовує скрипт, обробник подій чи подія. Приклади завдань: @@ -36,7 +36,7 @@ Наприклад, поки рушій виконує `script`, користувач може порухати мишкою, що спричинить появу події `mousemove`, та може вийти час, запрограмований в `setTimeout` і так далі. Ці завдання сформують чергу, як показано на схемі вище. -Задачі з черги виконуються за правилом "перший прийшов – перший пішов". Коли рушій браузера закінчить виконання `script`, він обробить подію `mousemove`, потім виконає обробник `setTimeout`, і так далі. +Задачі з черги виконуються за правилом "перший прийшов – перший пішов". Коли рушій браузера закінчить виконання `script`, він обробить подію `mousemove`, потім виконає обробник `setTimeout` тощо. Доволі просто наразі, чи не так? @@ -58,7 +58,7 @@ Щоб продемонструвати такий підхід, замість підсвічування для спрощення візьмемо функцію, яка рахує від `1` до `1000000000`. -Якщо ви запустите код нижче, рушій "зависне" на деякий час. Для серверного JS це буде явно видно, а якщо ви запускаєте це в браузері, то спробуйте понатискати інші кнопки на сторінці -- ви побачите, що жодна з подій не спрацює поки рахунок не завершиться. +Якщо ви запустите код нижче, рушій "зависне" на деякий час. Для серверного JS це буде явно видно, а якщо ви запускаєте це в браузері, то спробуйте понатискати інші кнопки на сторінці -- ви побачите, що жодна з подій не спрацює поки цей код не завершиться. ```js run let i = 0; @@ -152,9 +152,9 @@ count(); Чому? -Все просто: як ви знаєте, в браузера є мінімальна затримка в 4мс при багатьох вкладених викликах `setTimeout`. Навіть якщо ми встановимо `0`, насправді це буде `4ms` (або трохи більше). Тож чим раніше ми заплануємо виклик - тим швидше виконається код. +Все просто: як ви знаєте, в браузера є мінімальна затримка в 4мс при багатьох вкладених викликах `setTimeout`. Навіть якщо ми встановимо `0`, насправді це буде `4ms` (або трохи більше). Тож чим раніше ми заплануємо виклик -- тим швидше виконається код. -Отож, ми розбили ресурсозатратне завдання на частини - тепер воно не буде блокувати користувацький інтерфейс. І загальний час виконання практично не збільшиться. +Отож, ми розбили ресурсозатратне завдання на частини -- тепер воно не буде блокувати користувацький інтерфейс. І загальний час виконання практично не збільшиться. ## Приклад 2: індикація прогресу @@ -236,9 +236,9 @@ menu.onclick = function() { }; ``` -## Макрозавдання та Мікрозавдання +## Макрозавдання (Macrotasks) та Мікрозавдання (Microtasks) -Разом з *макрозавданнями*, описаними в цьому розділі, існують *мікрозавдання*, описані в розділі . +Разом з *макрозавданнями (macrotasks)*, описаними в цьому розділі, існують *мікрозавдання (microtasks)*, описані в розділі . Мікрозавдання приходять лише з нашого коду. Їх зазвичай створюють проміси: виконання обробника `.then/catch/finally` стає мікрозавданням. Мікрозавдання також використовуються "під капотом" `await`, так як це форма обробки проміса. @@ -259,9 +259,9 @@ alert("code"); Який тут буде порядок виконання? -1. `code` покажеться першим, тому що це звичайний синхронний виклик. -2. `promise` покажеться другим, тому що `.then` проходить через чергу мікрозадач, і виконується після поточного синхронного коду. -3. `timeout` покажеться останнім, тому що це макрозавдання. +1. `code` буде показано першим, тому що це звичайний синхронний виклик. +2. `promise` буде показано другим, тому що `.then` проходить через чергу мікрозадач, і виконується після поточного синхронного коду. +3. `timeout` буде показано останнім, тому що це макрозавдання. Більш детальна ілюстрація циклу подій виглядає так (порядок з верху до низу: спочатку script, потім мікрозавдання, рендеринг і так далі): @@ -301,7 +301,7 @@ alert("code"); ``` -## Підсумок +## Підсумки Більш детальний алгоритм циклу подій (хоч і спрощений порівняно зі [специфікацією](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model)): @@ -316,7 +316,7 @@ alert("code"); Щоб додати в чергу нове *макрозавдання*: - Використайте `setTimeout(f)` з нульовою затримкою. -Цей спосіб можна використати для розбиття великого важкообчислюваного завдання на частини, щоб браузер мав змогу реагувати на користувацькі події і показувати індикатор прогресу між ними. +Цей спосіб можна використати для розбиття великого ресурсозатратного завдання на частини, щоб браузер мав змогу реагувати на користувацькі події і показувати індикатор прогресу між ними. Також це використовується в обробниках подій, щоб відкласти дію до моменту повної обробки події (вспливання завершене). @@ -324,7 +324,7 @@ alert("code"); - Використайте `queueMicrotask(f)`. - Також обробники промісів виконуються в черзі мікрозавдань. -Жодні UI або мережеві події не обробляються між мікрозавданнями: мікрозавдання виконуються негайно один за одним. +Жодні UI або мережеві події не обробляються між мікрозавданнями: мікрозавдання виконуються негайно одне за одним. Тому `queueMicrotask` можна використати для асинхронного виконання фунції, але в одному й тому ж стані середовища.