From 6f9852034a36dee7f8b0782578cab0b6753c07f3 Mon Sep 17 00:00:00 2001 From: Tetiana Hordiienko Date: Sat, 15 Jan 2022 22:00:41 +0200 Subject: [PATCH 1/3] Promises chaining - add translation for article and task --- .../01-then-vs-catch/solution.md | 10 +- .../01-then-vs-catch/task.md | 6 +- 1-js/11-async/03-promise-chaining/article.md | 164 +++++++++--------- 3 files changed, 90 insertions(+), 90 deletions(-) diff --git a/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md b/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md index bdd1c643b..0cc785a95 100644 --- a/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md +++ b/1-js/11-async/03-promise-chaining/01-then-vs-catch/solution.md @@ -1,6 +1,6 @@ -The short answer is: **no, they are not equal**: +Коротка відповідь: **ні, вони не рівні**: -The difference is that if an error happens in `f1`, then it is handled by `.catch` here: +Різниця полягає в тому, що якщо помилка відбувається в `f1`, тоді її обробляє `.catch` тут: ```js run promise @@ -8,13 +8,13 @@ promise .catch(f2); ``` -...But not here: +...Але не тут: ```js run promise .then(f1, f2); ``` -That's because an error is passed down the chain, and in the second code piece there's no chain below `f1`. +Це тому, що помилка передається по ланцюжку, а в другому фрагменті коду немає ланцюжка нижче `f1`. -In other words, `.then` passes results/errors to the next `.then/catch`. So in the first example, there's a `catch` below, and in the second one there isn't, so the error is unhandled. +Іншими словами, `.then` передає результати/помилки наступному `.then/catch`. Отже, у першому прикладі нижче є `catch`, а в другому його немає, тому помилка не оброблена. diff --git a/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md b/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md index cefca60aa..e125e41b9 100644 --- a/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md +++ b/1-js/11-async/03-promise-chaining/01-then-vs-catch/task.md @@ -1,12 +1,12 @@ -# Promise: then versus catch +# Проміс: then проти catch -Are these code fragments equal? In other words, do they behave the same way in any circumstances, for any handler functions? +Чи рівні ці фрагменти коду? Іншими словами, чи поводяться вони однаково за будь-яких обставин для будь-яких функцій обробника? ```js promise.then(f1).catch(f2); ``` -Versus: +Проти: ```js promise.then(f1, f2); diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md index 6da4cb02e..2f975694e 100644 --- a/1-js/11-async/03-promise-chaining/article.md +++ b/1-js/11-async/03-promise-chaining/article.md @@ -1,13 +1,13 @@ -# Promises chaining +# Ланцюжок промісів -Let's return to the problem mentioned in the chapter : we have a sequence of asynchronous tasks to be performed one after another — for instance, loading scripts. How can we code it well? +Повернемося до проблеми, згаданої в розділі [Введення: колбеки](info:callbacks): у нас є послідовність асинхронних задач, які потрібно виконувати одну за одною — наприклад, завантаження скриптів. Як ми можемо це добре закодувати? -Promises provide a couple of recipes to do that. +Проміси надають кілька способів вирішення подібних задач. -In this chapter we cover promise chaining. +У цьому розділі ми розглянемо ланцюжок промісів. -It looks like this: +Він виглядає наступним чином: ```js run new Promise(function(resolve, reject) { @@ -32,25 +32,25 @@ new Promise(function(resolve, reject) { }); ``` -The idea is that the result is passed through the chain of `.then` handlers. +Ідея полягає в тому, що результат передається через ланцюжок `.then` обробників. -Here the flow is: -1. The initial promise resolves in 1 second `(*)`, -2. Then the `.then` handler is called `(**)`, which in turn creates a new promise (resolved with `2` value). -3. The next `then` `(***)` gets the result of the previous one, processes it (doubles) and passes it to the next handler. -4. ...and so on. +Ось потік виконання: +1. Початковий проміс успішно виконується через 1 секунду `(*)`, +2. Далі викликається обробник `.then` `(**)`, який у свою чергу, створює новий проміс (вирішується зі значенням `2`). +3. Наступний `then` `(***)` приймає результат попереднього, оброблює його (подвоює) та передає до наступного обробника. +4. ...і так далі. -As the result is passed along the chain of handlers, we can see a sequence of `alert` calls: `1` -> `2` -> `4`. +Коли результат передається по ланцюжку обробників, ми бачимо послідовність викликів `alert`: `1` -> `2` -> `4`. ![](promise-then-chain.svg) -The whole thing works, because every call to a `.then` returns a new promise, so that we can call the next `.then` on it. +Усе це працює тому, що кожний виклик `.then` повертає новий проміс, тому ми можемо викликати наступний `.then` на ньому. -When a handler returns a value, it becomes the result of that promise, so the next `.then` is called with it. +Коли обробник повертає значення, воно стає результатом того промісу, тому наступний `.then` викликається з цим значенням. -**A classic newbie error: technically we can also add many `.then` to a single promise. This is not chaining.** +**Класична помилка новачка: технічно ми також можемо додати багато `.then` до одного промісу. Та це не ланцюжок.** -For example: +Наприклад: ```js run let promise = new Promise(function(resolve, reject) { setTimeout(() => resolve(1), 1000); @@ -72,23 +72,23 @@ promise.then(function(result) { }); ``` -What we did here is just several handlers to one promise. They don't pass the result to each other; instead they process it independently. +Те, що ми зробили тут, — це додали лише кілька обробників до одного промісу. Вони не передають результат один одному; натомість вони обробляють його самостійно. -Here's the picture (compare it with the chaining above): +Ось малюнок (порівняйте його з ланцюжком вище): ![](promise-then-many.svg) -All `.then` on the same promise get the same result -- the result of that promise. So in the code above all `alert` show the same: `1`. +Усі `.then` на одному й тому самому промісі отримують той самий результат - результат цього промісу. Тож у коді вище усі `alert` показують те саме: `1`. -In practice we rarely need multiple handlers for one promise. Chaining is used much more often. +На практиці нам рідко потрібні кілька обробників для одного промісу. Набагато частіше використовується ланцюжок. -## Returning promises +## Повертаємо проміси -A handler, used in `.then(handler)` may create and return a promise. +Обробник, використанний в `.then(handler)` може створити й повернути проміс. -In that case further handlers wait until it settles, and then get its result. +У цьому випадку інші обробники чекають, поки він виконається, а потім отримають його результат. -For instance: +Наприклад: ```js run new Promise(function(resolve, reject) { @@ -120,15 +120,15 @@ new Promise(function(resolve, reject) { }); ``` -Here the first `.then` shows `1` and returns `new Promise(…)` in the line `(*)`. After one second it resolves, and the result (the argument of `resolve`, here it's `result * 2`) is passed on to handler of the second `.then`. That handler is in the line `(**)`, it shows `2` and does the same thing. +Тут перший `.then` показує `1` і повертає `new Promise(…)` у рядку `(*)`. Через одну секунду він вирішується, а результат (аргумент `resolve`, тут це `результат * 2`) передається обробнику другого `.then`. Цей обробник знаходиться в рядку `(**)`, він показує `2` і робить те ж саме. -So the output is the same as in the previous example: 1 -> 2 -> 4, but now with 1 second delay between `alert` calls. +Отже, результат такий же, як і в попередньому прикладі: 1 -> 2 -> 4, але тепер із затримкою в 1 секунду між викликами `alert`. -Returning promises allows us to build chains of asynchronous actions. +Повернення промісів дозволяє нам будувати ланцюжки асинхронних дій. -## Example: loadScript +## Приклад: loadScript -Let's use this feature with the promisified `loadScript`, defined in the [previous chapter](info:promise-basics#loadscript), to load scripts one by one, in sequence: +Давайте використовувати цю можливість з промісифікацією `loadScript`, визначеною у [попередньому розділі](info:promise-basics#loadscript), щоб завантажувати скрипти один за одним, у послідовності: ```js run loadScript("/article/promise-chaining/one.js") @@ -139,22 +139,22 @@ loadScript("/article/promise-chaining/one.js") return loadScript("/article/promise-chaining/three.js"); }) .then(function(script) { - // use functions declared in scripts - // to show that they indeed loaded + // викличемо функції, оголошені в скриптах + // щоб показати, що вони дійсно завантажені one(); two(); three(); }); ``` -This code can be made bit shorter with arrow functions: +Цей код можна зробити трохи коротшим за допомогою стрілкових функцій: ```js run loadScript("/article/promise-chaining/one.js") .then(script => loadScript("/article/promise-chaining/two.js")) .then(script => loadScript("/article/promise-chaining/three.js")) .then(script => { - // scripts are loaded, we can use functions declared there + // скрипти завантажені, ми можемо використовувати оголошені там функції one(); two(); three(); @@ -162,17 +162,17 @@ loadScript("/article/promise-chaining/one.js") ``` -Here each `loadScript` call returns a promise, and the next `.then` runs when it resolves. Then it initiates the loading of the next script. So scripts are loaded one after another. +Тут кожен виклик `loadScript` повертає проміс, а наступний `.then` запускається, коли він виконується. Потім він ініціює завантаження наступного сценарію. Таким чином, скрипти завантажуються один за одним. -We can add more asynchronous actions to the chain. Please note that the code is still "flat" — it grows down, not to the right. There are no signs of the "pyramid of doom". +Ми можемо додати більше асинхронних дій до ланцюжка. Зверніть увагу, що код все ще "плоский" — він росте вниз, а не вправо. Немає жодних ознак "піраміди приреченості". -Technically, we could add `.then` directly to each `loadScript`, like this: +Технічно ми можемо додати `.then` безпосередньо до кожного `loadScript`, наприклад: ```js run loadScript("/article/promise-chaining/one.js").then(script1 => { loadScript("/article/promise-chaining/two.js").then(script2 => { loadScript("/article/promise-chaining/three.js").then(script3 => { - // this function has access to variables script1, script2 and script3 + // ця функція має доступ до змінних script1, script2 і script3 one(); two(); three(); @@ -181,19 +181,19 @@ loadScript("/article/promise-chaining/one.js").then(script1 => { }); ``` -This code does the same: loads 3 scripts in sequence. But it "grows to the right". So we have the same problem as with callbacks. +Цей код робить те ж саме: завантажує 3 скрипти послідовно. Але він "росте вправо". Тож у нас та ж проблема, що й з колбеками. -People who start to use promises sometimes don't know about chaining, so they write it this way. Generally, chaining is preferred. +Люди, які починають використовувати проміси, іноді не знають про ланцюжок, тому пишуть це так. Як правило, перевага віддається ланцюжкам. -Sometimes it's ok to write `.then` directly, because the nested function has access to the outer scope. In the example above the most nested callback has access to all variables `script1`, `script2`, `script3`. But that's an exception rather than a rule. +Іноді нормально писати `.then` відразу, оскільки вкладена функція має доступ до зовнішньої області видимості. У наведеному вище прикладі найбільш вкладений колбек має доступ до всіх змінних `script1`, `script2`, `script3`. Але це швидше виняток, ніж правило. ````smart header="Thenables" -To be precise, a handler may return not exactly a promise, but a so-called "thenable" object - an arbitrary object that has a method `.then`. It will be treated the same way as a promise. +Якщо бути точним, обробник може повернути не зовсім проміс, а так званий об’єкт "thenable" - довільний об’єкт, який має метод `.then`. Це буде розглядатися так само, як проміс. -The idea is that 3rd-party libraries may implement "promise-compatible" objects of their own. They can have an extended set of methods, but also be compatible with native promises, because they implement `.then`. +Ідея полягає в тому, що сторонні бібліотеки можуть реалізовувати власні промісо-сумісні об’єкти. Вони можуть мати розширений набір методів, але також можуть бути сумісні з нативними промісами, оскільки вони реалізують `.then`. -Here's an example of a thenable object: +Ось приклад такого об’єкта: ```js run class Thenable { @@ -202,7 +202,7 @@ class Thenable { } then(resolve, reject) { alert(resolve); // function() { native code } - // resolve with this.num*2 after the 1 second + // буде успішно виконано з аргументом this.num*2 через 1 секунду setTimeout(() => resolve(this.num * 2), 1000); // (**) } } @@ -213,70 +213,70 @@ new Promise(resolve => resolve(1)) return new Thenable(result); // (*) */!* }) - .then(alert); // shows 2 after 1000ms + .then(alert); // показує 2 через 1000 мс ``` -JavaScript checks the object returned by the `.then` handler in line `(*)`: if it has a callable method named `then`, then it calls that method providing native functions `resolve`, `reject` as arguments (similar to an executor) and waits until one of them is called. In the example above `resolve(2)` is called after 1 second `(**)`. Then the result is passed further down the chain. +JavaScript перевіряє об’єкт, повернутий обробником `.then` у рядку `(*)`: якщо він має викликаний метод з ім’ям `then`, тоді він викликає цей метод, та надає власні функції `resolve`, `reject` як аргументи (подібно виконавцю) і чекає, поки один з них не буде викликаний. У наведеному вище прикладі `resolve(2)` викликається через 1 секунду `(**)`. Потім результат передається далі по ланцюжку. -This feature allows us to integrate custom objects with promise chains without having to inherit from `Promise`. +Ця функція дозволяє нам інтегрувати власні об’єкти з ланцюжками промісів без успадкування від `Promise`. ```` -## Bigger example: fetch +## Більш складний приклад: fetch -In frontend programming promises are often used for network requests. So let's see an extended example of that. +У інтерфейсному програмуванні проміси часто використовуються для мережевих запитів. Тож давайте подивимося на розширений приклад цього. -We'll use the [fetch](info:fetch) method to load the information about the user from the remote server. It has a lot of optional parameters covered in [separate chapters](info:fetch), but the basic syntax is quite simple: +Ми будемо використовувати метод [fetch](info:fetch), щоб завантажити інформацію про користувача з віддаленого сервера. Він має багато опціональних параметрів, які розглядаються в [окремих розділах](info:fetch), але основний синтаксис досить простий: ```js let promise = fetch(url); ``` -This makes a network request to the `url` and returns a promise. The promise resolves with a `response` object when the remote server responds with headers, but *before the full response is downloaded*. +Зазначений код робить мережевий запит до `url` і повертає проміс. Проміс розв’язується за допомогою об’єкта `response`, коли віддалений сервер відповідає заголовками, але *до завантаження повної відповіді*. -To read the full response, we should call the method `response.text()`: it returns a promise that resolves when the full text is downloaded from the remote server, with that text as a result. +Щоб прочитати повну відповідь, ми повинні викликати метод `response.text()`: він повертає проміс, який виконується, коли повний текст завантажується з віддаленого сервера, і містить цей текст як результат. -The code below makes a request to `user.json` and loads its text from the server: +Наведений нижче код робить запит до `user.json` і завантажує його текст із сервера: ```js run fetch('/article/promise-chaining/user.json') - // .then below runs when the remote server responds + // .then нижче запускається, коли віддалений сервер відповідає .then(function(response) { - // response.text() returns a new promise that resolves with the full response text - // when it loads + // response.text() повертає новий проміс, який вирішується з повним текстом відповіді, + // коли він завантажується return response.text(); }) .then(function(text) { - // ...and here's the content of the remote file + // ...а ось вміст віддаленого файлу alert(text); // {"name": "iliakan", "isAdmin": true} }); ``` -The `response` object returned from `fetch` also includes the method `response.json()` that reads the remote data and parses it as JSON. In our case that's even more convenient, so let's switch to it. +Об’єкт `response`, повернутий із `fetch`, також включає метод `response.json()`, який зчитує віддалені дані у форматі JSON. У нашому випадку це ще зручніше, тож перейдемо до нього. -We'll also use arrow functions for brevity: +Ми також будемо використовувати стрілкові функції для стислості: ```js run -// same as above, but response.json() parses the remote content as JSON +// те саме, що й вище, але response.json() зчитує віддалений контент у форматі JSON fetch('/article/promise-chaining/user.json') .then(response => response.json()) - .then(user => alert(user.name)); // iliakan, got user name + .then(user => alert(user.name)); // iliakan, отримали ім’я користувача ``` -Now let's do something with the loaded user. +Тепер давайте зробимо щось із завантаженим користувачем. -For instance, we can make one more request to GitHub, load the user profile and show the avatar: +Наприклад, ми можемо зробити ще один запит до GitHub, завантажити профіль користувача та показати аватар: ```js run -// Make a request for user.json +// Запитуємо user.json fetch('/article/promise-chaining/user.json') - // Load it as json + // Завантажуємо дані у форматі json .then(response => response.json()) - // Make a request to GitHub + // Робимо запит до GitHub .then(user => fetch(`https://api.github.com/users/${user.name}`)) - // Load the response as json + // Завантажуємо відповідь у форматі json .then(response => response.json()) - // Show the avatar image (githubUser.avatar_url) for 3 seconds (maybe animate it) + // Показуємо аватар (githubUser.avatar_url) протягом 3 секунд (можливо, з анімацією) .then(githubUser => { let img = document.createElement('img'); img.src = githubUser.avatar_url; @@ -287,13 +287,13 @@ fetch('/article/promise-chaining/user.json') }); ``` -The code works; see comments about the details. However, there's a potential problem in it, a typical error for those who begin to use promises. +Код працює; дивіться коментарі щодо деталей. Однак у цьому є потенційна проблема, типова помилка для тих, хто починає використовувати проміси. -Look at the line `(*)`: how can we do something *after* the avatar has finished showing and gets removed? For instance, we'd like to show a form for editing that user or something else. As of now, there's no way. +Подивіться на рядок `(*)`: як ми можемо щось зробити *після* того, як аватар закінчить відображатися і видалиться? Наприклад, ми хотіли б показати форму для редагування цього користувача чи щось інше. Поки що такої можливості немає. -To make the chain extendable, we need to return a promise that resolves when the avatar finishes showing. +Щоб ланцюжок міг розширюватися, нам потрібно повернути проміс, який розв’язується, коли аватар закінчує відображатися. -Like this: +Ось так: ```js run fetch('/article/promise-chaining/user.json') @@ -315,15 +315,15 @@ fetch('/article/promise-chaining/user.json') */!* }, 3000); })) - // triggers after 3 seconds - .then(githubUser => alert(`Finished showing ${githubUser.name}`)); + // спрацьовує через 3 секунди + .then(githubUser => alert(`Завершили показ ${githubUser.name}`)); ``` -That is, the `.then` handler in line `(*)` now returns `new Promise`, that becomes settled only after the call of `resolve(githubUser)` in `setTimeout` `(**)`. The next `.then` in the chain will wait for that. +Тобто обробник `.then` у рядку `(*)` тепер повертає `new Promise`, який перейде у стан "виконаний" лише після виклику `resolve(githubUser)` у `setTimeout` `(**)`. Наступний `.then` в ланцюжку буде чекати цього. -As a good practice, an asynchronous action should always return a promise. That makes it possible to plan actions after it; even if we don't plan to extend the chain now, we may need it later. +Як хороша практика, асинхронна дія завжди повинна повертати проміс. Це дає можливість планувати дії після нього; навіть якщо ми не плануємо розширювати ланцюжок зараз, можливо, це нам знадобиться пізніше. -Finally, we can split the code into reusable functions: +Нарешті, ми можемо розділити код на функції, що можуть бути перевикористані: ```js run function loadJson(url) { @@ -349,18 +349,18 @@ function showAvatar(githubUser) { }); } -// Use them: +// Використаємо їх: loadJson('/article/promise-chaining/user.json') .then(user => loadGithubUser(user.name)) .then(showAvatar) - .then(githubUser => alert(`Finished showing ${githubUser.name}`)); + .then(githubUser => alert(`Завершили показ ${githubUser.name}`)); // ... ``` -## Summary +## Підсумок -If a `.then` (or `catch/finally`, doesn't matter) handler returns a promise, the rest of the chain waits until it settles. When it does, its result (or error) is passed further. +Якщо обробник `.then` (або `catch/finally`, не має різниці) повертає проміс, решта ланцюжка чекає, доки він виконається. Коли це відбувається, його результат (або помилка) передається далі. -Here's a full picture: +Ось повна картина: ![](promise-handler-variants.svg) From 4359faa4305ec3a6b206b9552e4e99b8102f8ff8 Mon Sep 17 00:00:00 2001 From: Tetiana Hordiienko Date: Mon, 17 Jan 2022 16:04:05 +0200 Subject: [PATCH 2/3] Promises chaining - add translation for images --- .../03-promise-chaining/promise-handler-variants.svg | 2 +- images.yml | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/1-js/11-async/03-promise-chaining/promise-handler-variants.svg b/1-js/11-async/03-promise-chaining/promise-handler-variants.svg index 664a4dbeb..9a5f21aa7 100644 --- a/1-js/11-async/03-promise-chaining/promise-handler-variants.svg +++ b/1-js/11-async/03-promise-chaining/promise-handler-variants.svg @@ -1 +1 @@ -return valuereturn promisethrow errorstate: "fulfilled" result: valuestate: "rejected" result: error...with the result of the new promise...state: "pending" result: undefinedthe call of .then(handler) always returns a promise:if handler ends with…that promise settles with: \ No newline at end of file +поверненням значенняповерненням промісупомилкоюstate: "fulfilled" result: valuestate: "rejected" result: error...з результатом нового промісу...state: "pending" result: undefinedвиклик .then(handler) завжди повертає проміс:якщо handler завершується…цей проміс завершується з: diff --git a/images.yml b/images.yml index 84701c367..e404877ed 100644 --- a/images.yml +++ b/images.yml @@ -121,6 +121,18 @@ try-catch-flow.svg: '}': '' // code...: '// код...' +promise-handler-variants.svg: + _defaults: + position: "center" + ...with the result: '...з результатом' + of the new promise...: 'нового промісу...' + 'the call of .then(handler) always returns a promise:': 'виклик .then(handler) завжди повертає проміс:' + if handler ends with…: 'якщо handler завершується…' + return value: 'поверненням значення' + return promise: 'поверненням промісу' + throw error: 'помилкою' + 'that promise settles with:': 'цей проміс завершується з:' + statusbarButtonGlyphs.svg: '!': '' From e46575311cc154eb4e20145e1639d2ad9dbb3d58 Mon Sep 17 00:00:00 2001 From: Taras Date: Mon, 17 Jan 2022 16:53:39 +0200 Subject: [PATCH 3/3] Apply suggestions from code review --- 1-js/11-async/03-promise-chaining/article.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/1-js/11-async/03-promise-chaining/article.md b/1-js/11-async/03-promise-chaining/article.md index 2f975694e..c941b08c6 100644 --- a/1-js/11-async/03-promise-chaining/article.md +++ b/1-js/11-async/03-promise-chaining/article.md @@ -82,7 +82,7 @@ promise.then(function(result) { На практиці нам рідко потрібні кілька обробників для одного промісу. Набагато частіше використовується ланцюжок. -## Повертаємо проміси +## Повернення промісів Обробник, використанний в `.then(handler)` може створити й повернути проміс. @@ -222,7 +222,7 @@ JavaScript перевіряє об’єкт, повернутий обробни ```` -## Більш складний приклад: fetch +## Складніший приклад: fetch У інтерфейсному програмуванні проміси часто використовуються для мережевих запитів. Тож давайте подивимося на розширений приклад цього. @@ -357,7 +357,7 @@ loadJson('/article/promise-chaining/user.json') // ... ``` -## Підсумок +## Підсумки Якщо обробник `.then` (або `catch/finally`, не має різниці) повертає проміс, решта ланцюжка чекає, доки він виконається. Коли це відбувається, його результат (або помилка) передається далі. pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy