From f185d3947b7809afa39bf2099f0ff39f3a20cd50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sad=C4=B1k=20=C3=9Cnal=20=C3=87ok=C3=BCnl=C3=BC?= Date: Sun, 1 Aug 2021 08:41:11 +0300 Subject: [PATCH 1/5] Create article.md --- 2-ui/99-ui-misc/03-event-loop/article.md | 339 +++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 2-ui/99-ui-misc/03-event-loop/article.md diff --git a/2-ui/99-ui-misc/03-event-loop/article.md b/2-ui/99-ui-misc/03-event-loop/article.md new file mode 100644 index 000000000..3ea0c2c57 --- /dev/null +++ b/2-ui/99-ui-misc/03-event-loop/article.md @@ -0,0 +1,339 @@ + +# Event loop: microtasks and macrotasks + +Browser JavaScript execution flow, as well as in Node.js, is based on an *event loop*. + +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. + +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. + +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. + +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. + +This looks prettier: + +```html run +
+ + +``` + +Now the `
` shows increasing values of `i`, a kind of a progress bar. + + +## Use case 3: doing something after the event + +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`. + +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. + +```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. + +There's also a special function `queueMicrotask(func)` that queues `func` for execution in the microtask queue. + +**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")); + +Promise.resolve() + .then(() => alert("promise")); + +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. + +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): + +![](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`. + +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: + +```html run +
+ + +``` + +## 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)): + +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. + +To schedule a new *macrotask*: +- Use zero delayed `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. + +There's no UI or network event handling between microtasks: they run immediately one after another. + +So one may want to `queueMicrotask` to execute a function asynchronously, but within the environment state. + +```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). + +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 do not have access to DOM, so they are useful, mainly, for calculations, to use multiple CPU cores simultaneously. +``` From f4448781b5f81a7ba7ec38dc5b6e590af7def5ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sad=C4=B1k=20=C3=9Cnal=20=C3=87ok=C3=BCnl=C3=BC?= Date: Sun, 1 Aug 2021 08:42:31 +0300 Subject: [PATCH 2/5] Add files via upload --- 2-ui/99-ui-misc/03-event-loop/eventLoop.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 2-ui/99-ui-misc/03-event-loop/eventLoop.svg diff --git a/2-ui/99-ui-misc/03-event-loop/eventLoop.svg b/2-ui/99-ui-misc/03-event-loop/eventLoop.svg new file mode 100644 index 000000000..f7de0b6ad --- /dev/null +++ b/2-ui/99-ui-misc/03-event-loop/eventLoop.svg @@ -0,0 +1 @@ +...mousemovescriptevent loopmacrotask queuesetTimeout \ No newline at end of file From 6f3e1f2dfd3470c5c0de3519723488fd053fb6fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sad=C4=B1k=20=C3=9Cnal=20=C3=87ok=C3=BCnl=C3=BC?= Date: Sun, 1 Aug 2021 08:43:02 +0300 Subject: [PATCH 3/5] Add files via upload --- 2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg 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 new file mode 100644 index 000000000..201d9a14a --- /dev/null +++ b/2-ui/99-ui-misc/03-event-loop/eventLoop-full.svg @@ -0,0 +1 @@ +...mousemoveevent looprendermicrotasksrendermicrotasksscriptsetTimeout \ No newline at end of file From d339746e0edd32e0d883504c2c0081825a04b946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sad=C4=B1k=20=C3=9Cnal=20=C3=87ok=C3=BCnl=C3=BC?= Date: Sun, 1 Aug 2021 10:17:59 +0300 Subject: [PATCH 4/5] Update article.md --- 2-ui/99-ui-misc/03-event-loop/article.md | 145 ++++++++++++----------- 1 file changed, 73 insertions(+), 72 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..77e072233 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 +# Olay döngüsü: microtasks ve macrotasks -Browser JavaScript execution flow, as well as in Node.js, is based on an *event loop*. +Node.js'de olduğu gibi tarayıcı JavaScript yürütme akışı da bir *olay döngüsüne* dayanır. -Understanding how event loop works is important for optimizations, and sometimes for the right architecture. +Olay döngüsünün nasıl çalıştığını anlamak, optimizasyonlar ve bazen de doğru mimari için önemlidir. -In this chapter we first cover theoretical details about how things work, and then see practical applications of that knowledge. +Bu bölümde önce işlerin nasıl yürüdüğüyle ilgili teorik ayrıntıları ele alacağız ve ardından bu bilginin pratik uygulamalarını göreceğiz. -## Event Loop +## Olay Döngüsü -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. +*Olay döngüsü* kavramı çok basittir. JavaScript motorunun görevleri beklediği, yürüttüğü ve daha sonra uyuyarak daha fazla görev beklediği sonsuz bir döngü vardır. -The general algorithm of the engine: +Motorun genel algoritması: -1. While there are tasks: - - execute them, starting with the oldest task. -2. Sleep until a task appears, then go to 1. +1. Görevler varken: + - en eski görevden başlayarak bunları yürütün. +2. Bir görev görünene kadar uyuyun, ardından 1'e gidin. -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. +Bu, bir sayfaya göz atarken gördüğümüz şeyin biçimselleştirilmesidir. JavaScript motoru çoğu zaman hiçbir şey yapmaz, yalnızca bir script/işleyici/olay etkinleştirildiğinde çalışır. -Examples of tasks: +Görev örnekleri: -- When an external script ` ``` -...But we also may want to show something during the task, e.g. a progress bar. +...Ancak görev sırasında da bir şey göstermek isteyebiliriz, örneğin bir ilerleme çubuğu. -If we split the heavy task into pieces using `setTimeout`, then changes are painted out in-between them. +Eğer ağır görevi `setTimeout` kullanarak parçalara ayırırsak, o zaman değişiklikler aralarında boyanır. -This looks prettier: +Bu daha güzel görünüyor: ```html run
@@ -197,7 +198,7 @@ This looks prettier: function count() { - // do a piece of the heavy job (*) + // ağır işin bir parçasını yap (*) do { i++; progress.innerHTML = i; @@ -213,14 +214,14 @@ This looks prettier: ``` -Now the `
` shows increasing values of `i`, a kind of a progress bar. +Şimdi `
`, bir tür ilerleme çubuğu olan `i`'nin artan değerlerini gösteriyor. -## Use case 3: doing something after the event +## Kullanım Senaryosu 3: olaydan sonra bir şeyler yapmak -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`. +Bir olay işleyicide, bazı eylemleri olay kabarıp tüm seviyelerde işlenene kadar ertelemeye karar verebiliriz. Bunu, kodu sıfır gecikmeli `setTimeout` içine sararak yapabiliriz. -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. + bölümünde bir örnek gördük: `menu-open` özel olayı(custom event) `setTimeout` içinde gönderilir, böylece click" olayı tamamen işlendikten sonra gerçekleşir. ```js menu.onclick = function() { @@ -236,17 +237,17 @@ menu.onclick = function() { }; ``` -## Macrotasks and Microtasks +## Macrotasks ve Microtasks -Along with *macrotasks*, described in this chapter, there are *microtasks*, mentioned in the chapter . +Bu bölümde açıklanan *macrotasks* ile birlikte, bölümünde bahsedilen *microtasks* vardır. -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. +Microtask'ler yalnızca kodumuzdan gelir. Genellikle promise'larla oluşturulurlar: `.then/catch/finally` işleyicisinin yürütülmesi bir microtask haline gelir. Microtask'ler, bir başka promise işleme biçimi olduğu için, `wait`'in "örtüsü altında" da kullanılır. -There's also a special function `queueMicrotask(func)` that queues `func` for execution in the microtask queue. +Ayrıca, microtask kuyruğunda yürütülmek üzere `func`'u sıraya sokan özel bir `queueMicrotask(func)` fonksiyonu da vardır. -**Immediately after every *macrotask*, the engine executes all tasks from *microtask* queue, prior to running any other macrotasks or rendering or anything else.** +**Her macrotask'dan hemen sonra, motor, diğer macrotask'ları çalıştırmadan veya oluşturmadan veya başka herhangi bir şeyden önce tüm görevleri microtask kuyruğundan yürütür.** -For instance, take a look: +Örneğin, bir göz atın: ```js run setTimeout(() => alert("timeout")); From 841b9219141d7bfe099501dccb86807c6b0ee3e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sad=C4=B1k=20=C3=9Cnal=20=C3=87ok=C3=BCnl=C3=BC?= Date: Sun, 1 Aug 2021 21:04:31 +0300 Subject: [PATCH 5/5] Update article.md --- 2-ui/99-ui-misc/03-event-loop/article.md | 71 ++++++++++++------------ 1 file changed, 36 insertions(+), 35 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 77e072233..26a80afe9 100644 --- a/2-ui/99-ui-misc/03-event-loop/article.md +++ b/2-ui/99-ui-misc/03-event-loop/article.md @@ -221,25 +221,25 @@ Bu daha güzel görünüyor: Bir olay işleyicide, bazı eylemleri olay kabarıp tüm seviyelerde işlenene kadar ertelemeye karar verebiliriz. Bunu, kodu sıfır gecikmeli `setTimeout` içine sararak yapabiliriz. - bölümünde bir örnek gördük: `menu-open` özel olayı(custom event) `setTimeout` içinde gönderilir, böylece click" olayı tamamen işlendikten sonra gerçekleşir. + bölümünde bir örnek gördük: `menu-open` özel olayı(custom event) `setTimeout` içinde gönderilir, böylece "click" olayı tamamen işlendikten sonra gerçekleşir. ```js menu.onclick = function() { // ... - // create a custom event with the clicked menu item data + // tıklanan menü öğesi verileriyle özel bir olay oluşturun let customEvent = new CustomEvent("menu-open", { bubbles: true }); - // dispatch the custom event asynchronously + // özel olayı eşzamansız(asynchronously) olarak gönder setTimeout(() => menu.dispatchEvent(customEvent)); }; ``` ## Macrotasks ve Microtasks -Bu bölümde açıklanan *macrotasks* ile birlikte, bölümünde bahsedilen *microtasks* vardır. +Bu bölümde açıklanan *macrotask*'ler ile birlikte, bölümünde bahsedilen *microtask*'ler vardır. Microtask'ler yalnızca kodumuzdan gelir. Genellikle promise'larla oluşturulurlar: `.then/catch/finally` işleyicisinin yürütülmesi bir microtask haline gelir. Microtask'ler, bir başka promise işleme biçimi olduğu için, `wait`'in "örtüsü altında" da kullanılır. @@ -258,23 +258,24 @@ Promise.resolve() alert("code"); ``` -What's going to be the order here? +Buradaki sıra ne olacak? -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. Sıradan bir eşzamanlı(synchronous) çağrı olduğu için önce `kod` gösterilir. +2. `promise` ikinci sıradadır, çünkü `.then` microtask kuyruğundan geçer ve geçerli koddan sonra çalışır. +3. `timeout`'u en son gösterir, çünkü bu bir macrotask'dir. -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): +Daha zengin olay döngüsü resmi şöyle görünür (sıra yukarıdan aşağıya doğrudur, yani: önce script, ardından microtask'ler, oluşturma(rendering) vb.): ![](eventLoop-full.svg) -All microtasks are completed before any other event handling or rendering or any other macrotask takes place. +Tüm microtask'ler, başka herhangi bir olay işleme(handling) veya oluşturma(rendering) veya başka herhangi bir macrotask gerçekleşmeden önce tamamlanır. -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. +Uygulama ortamının microtask'ler arasında temelde aynı olmasını (fare koordinat değişikliği yok, yeni ağ verisi yok, vb.) garanti ettiği için bu önemlidir. -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`. +Bir fonksiyonu eşzamansız(asynchronously) olarak (geçerli koddan sonra) yürütmek istiyorsak, ancak değişiklikler oluşturulmadan(rendered) veya yeni olaylar işlenmeden(handled) önce, bunu `queueMicrotask` ile zamanlayabiliriz. 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: +Burada, daha önce gösterilene benzer bir "sayan ilerleme çubuğu" örneği verilmiştir, ancak `setTimeout` yerine `queueMicrotask` kullanılmıştır. En sonunda oluştuğunu(render) görebilirsiniz. Tıpkı senkron kod gibi: ```html run
@@ -284,7 +285,7 @@ Here's an example with "counting progress bar", similar to the one shown previou function count() { - // do a piece of the heavy job (*) + // ağır işin bir parçasını yap (*) do { i++; progress.innerHTML = i; @@ -302,39 +303,39 @@ Here's an example with "counting progress bar", similar to the one shown previou ``` -## Summary +## Özet -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)): +Daha ayrıntılı bir olay döngüsü algoritması (yine de [spesifikasyona](https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model) kıyasla basitleştirilmiş olsa da): -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. En eski görevi *macrotask* kuyruğundan ayırın ve çalıştırın (ör. "script"). +2. Tüm *microtask*'leri yürütün: + - Microtask kuyruğu boş değilken: + - En eski microtask'i sıraya alın ve çalıştırın. +3. Varsa oluşturme(render) değişiklikleri. +4. Macrotask kuyruğu boşsa, bir macrotask görünene kadar bekleyin. +5. 1.Adıma gidin. -To schedule a new *macrotask*: -- Use zero delayed `setTimeout(f)`. +Yeni bir *macrotask* zamanlamak için: +- Sıfır gecikmeli `setTimeout(f)` kullanın. -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. +Bu, tarayıcının kullanıcı olaylarına tepki verebilmesi ve aralarındaki ilerlemeyi gösterebilmesi için büyük bir hesaplama ağırlıklı görevi parçalara ayırmak için kullanılabilir. -Also, used in event handlers to schedule an action after the event is fully handled (bubbling done). +Ayrıca, olay tamamen işlendikten (köpürme işlemi) sonra bir eylem zamanlamak için olay işleyicilerinde kullanılır. -To schedule a new *microtask* -- Use `queueMicrotask(f)`. -- Also promise handlers go through the microtask queue. +Yeni bir *microtask* planlamak için +- `queueMicrotask(f)` kullanın. +- Ayrıca promise işleyicileri microtask kuyruğundan geçer. -There's no UI or network event handling between microtasks: they run immediately one after another. +Microtask'ler arasında UI veya ağ olayı işleme yoktur: Bunlar birbiri ardına hemen çalışır. -So one may want to `queueMicrotask` to execute a function asynchronously, but within the environment state. +Bu nedenle, bir fonksiyonu eşzamansız(asynchronously) olarak ancak ortam durumu içinde yürütmek için `queueMicrotask` isteyebilirsiniz. ```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). +Olay döngüsünü engellememesi gereken uzun ağır hesaplamalar için [Web Workers](https://html.spec.whatwg.org/multipage/workers.html)'ı kullanabiliriz. -That's a way to run code in another, parallel thread. +Bu, başka bir paralel iş parçacığında(thread) kod çalıştırmanın bir yoludur. -Web Workers can exchange messages with the main process, but they have their own variables, and their own event loop. +Web Workers ana süreçle mesaj alışverişinde bulunabilirler, ancak kendi değişkenleri ve kendi olay döngüleri vardır. -Web Workers do not have access to DOM, so they are useful, mainly, for calculations, to use multiple CPU cores simultaneously. +Web Worker'larının DOM'a erişimi yoktur, bu nedenle, esas olarak hesaplamalar için, aynı anda birden fazla CPU çekirdeği kullanmak için yararlıdırlar. ```