From 14d0c948198ecdf35845fa2a82cb09b70c2e4521 Mon Sep 17 00:00:00 2001 From: Vitalii Perehonchuk Date: Fri, 9 Aug 2024 15:41:16 +0300 Subject: [PATCH 01/29] update(JS): web/javascript/reference/global_objects/promise (#3021) * update(JS): web/javascript/reference/global_objects/promise * Apply suggestions from code review * update(JS): web/javascript/reference/global_objects/promise * update(JS): web/javascript/reference/global_objects/promise * update(JS): web/javascript/reference/global_objects/promise * update(JS): web/javascript/reference/global_objects/promise * Apply suggestions from code review Co-authored-by: Alina Listunova --------- Co-authored-by: Alina Listunova --- .../reference/global_objects/promise/index.md | 65 ++++++++++--------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/files/uk/web/javascript/reference/global_objects/promise/index.md b/files/uk/web/javascript/reference/global_objects/promise/index.md index ecc09b240c..1a9ecea13f 100644 --- a/files/uk/web/javascript/reference/global_objects/promise/index.md +++ b/files/uk/web/javascript/reference/global_objects/promise/index.md @@ -13,7 +13,7 @@ browser-compat: javascript.builtins.Promise ## Опис -**`Promise`** – це заміна для значення, яке, як правило, невідоме на момент, коли проміс створюється. Він дає змогу прив'язати обробники до результату успішного виконання чи до причини невдачі асинхронної операції. Це дає асинхронним методам змогу повертати значення схоже до того, як це роблять синхронні функції. Замість повернути одразу кінцеве значення метод повертає _promise - зобов'язання_ надати це значення в якийсь момент у майбутньому. +`Promise` – це заміна для значення, яке, як правило, невідоме на момент, коли проміс створюється. Він дає змогу прив'язати обробники до результату успішного виконання чи до причини невдачі асинхронної операції. Це дає асинхронним методам змогу повертати значення схоже до того, як це роблять синхронні функції. Замість повернути одразу кінцеве значення метод повертає _promise - зобов'язання_ надати це значення в якийсь момент у майбутньому. `Promise` завжди знаходиться в одному з таких станів: @@ -28,7 +28,7 @@ _Кінцевий стан_ промісу, який знаходиться в ![Діаграма, що показує, як стан промісу змінюється між очікуванням, сповненістю та відхиленістю за допомогою обробників then/catch. Проміс в стані очікування може стати або сповненим, або відхиленим. Якщо він був сповнений, то виконується обробник "при сповненні", або ж перший параметр метода then(), і продовжуються подальші асинхронні дії. Якщо проміс був відхилений, то виконується обробник помилки, або переданий як другий параметр метода then(), або як єдиний параметр метода catch().](promises.png) -Також можна зустріти використання з промісами терміну _вирішений_, – це означає, що проміс залагоджений або "замкнений" на відповідність кінцевому стану іншого проміса, і подальше його вирішення чи відхилення буде безрезультатним. Документ [Стани та долі (англ.)](https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md) з оригінальної пропозиції промісів містить більше деталей щодо термінології промісів. У розмовній мові "вирішені" проміси нерідко еквівалентні до "сповнених", але, як це показано в "Станах та долях", вирішені проміси також можуть очікувати чи бути відхиленими. Наприклад: +Також можна зустріти використання з промісами терміну _вирішений_, – це означає, що проміс залагоджений або "замкнений" на відповідність кінцевому стану іншого проміса, і подальше його вирішення чи відхилення буде безрезультатним. Документ [Стани та долі](https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md) з оригінальної пропозиції промісів містить більше деталей щодо термінології промісів. У розмовній мові "вирішені" проміси нерідко еквівалентні до "сповнених", але, як це показано в "Станах та долях", вирішені проміси також можуть очікувати чи бути відхиленими. Наприклад: ```js new Promise((resolveOuter) => { @@ -42,13 +42,14 @@ new Promise((resolveOuter) => { Цей проміс є вже _вирішеним_ на час створення (бо `resolveOuter` викликана синхронно), але він вирішений з іншим промісом, а тому не буде _сповненим_ іще 1 секунду, поки не сповниться внутрішній проміс. На практиці "вирішення" нерідко виконується за лаштунками й не може відстежуватися, натомість сповнення й відхилення проміса – можуть. -> **Примітка:** Декілька інших мов мають механізми лінивих та відкладених обчислень, котрі теж звуться "промісами", наприклад, Scheme. Проміси в JavaScript представляють процеси, що вже відбуваються, котрі можна зв'язати в ланцюжок за допомогою функцій зворотного виклику. Якщо треба ліниво обчислити вираз, слід розглянути можливість використання функції без аргументів, наприклад, `f = () => expression`, що породжує ліниво обчислений вираз, обчислити котрий можна за допомогою `f()`. +> [!NOTE] +> Декілька інших мов мають механізми лінивих та відкладених обчислень, котрі теж звуться "промісами", наприклад, Scheme. Проміси в JavaScript представляють процеси, що вже відбуваються, котрі можна зв'язати в ланцюжок за допомогою функцій зворотного виклику. Якщо треба ліниво обчислити вираз, слід розглянути можливість використання функції без аргументів, наприклад, `f = () => expression`, що породжує ліниво обчислений вираз, обчислити котрий можна за допомогою `f()`. -### Ланцюжки промісів +Сам `Promise` не має протоколу першого класу для скасування, проте можливо, що вдасться безпосередньо скасувати асинхронну операцію, що за ним стоїть, зазвичай використовуючи [`AbortController`](/uk/docs/Web/API/AbortController). -Методи {{jsxref("Promise.prototype.then()")}}, {{jsxref("Promise.prototype.catch()")}} і {{jsxref("Promise.prototype.finally()")}} використовуються, щоб приєднати якусь наступну дію до промісу, який залагоджується. Оскільки ці методи повертають проміси, їх виклики можна об'єднати в ланцюжок. +### Ланцюжки промісів -Метод `.then()` приймає до двох аргументів; перший — це функція зворотного виклику для сповнення промісу, а другий — відповідно, функція для його відхилення. Кожний `.then()` повертає новостворений об'єкт промісу, який далі може (необов'язково) використовуватися для нарощування ланцюжка викликів, як от: +Методи промісів {{jsxref("Promise/then", "then()")}}, {{jsxref("Promise/catch", "catch()")}} і {{jsxref("Promise/finally", "finally()")}} використовуються, щоб приєднати якусь наступну дію до промісу, який залагоджується. Метод `.then()` приймає до двох аргументів; перший — це функція зворотного виклику на випадок сповнення промісу, а другий — відповідно, на випадок його відхилення. Методи `catch()` і `finally()` за лаштунками викликають `then()` і роблять обробку помилок менш громіздкою. Наприклад, насправді `catch()` – це просто `then()` без передачі обробника сповнення. Оскільки ці методи повертають проміси, їхні виклики можна об'єднувати в ланцюжки. Наприклад: ```js const myPromise = new Promise((resolve, reject) => { @@ -63,9 +64,21 @@ myPromise .then(handleFulfilledC, handleRejectedC); ``` -Процес продовжується до наступної ланки ланцюжка, навіть якщо у наступний `.then()` не було передано функцію зворотного виклику. Таким чином, ланцюжок може спокійно оминати кожний виклик функції _відхилення_ аж до останнього `.catch()`. +Тут використовується наступна термінологія: _початковий проміс_ – це той, на якому викликано `then`; _новий проміс_ – це той, що повернений `then`. Два обробники, передані `then`, називаються _обробником сповнення_ та _обробником відхилення_ відповідно. + +Стан залагодження початкового проміса визначає обробник, який буде виконано. + +- Якщо початковий проміс сповнено, то викликається обробник сповнення зі значенням сповнення. +- Якщо початковий проміс відхилено, то викликається обробник відхилення з причиною відхилення. + +Завершення функції-обробника визначає стан залагодження нового проміса: + +- Якщо функція-обробник повертає значення [очікуваного об'єкта](#ochikuvani), то новий проміс залагоджується в той самий стан, що й повернутий проміс. +- Якщо функція-обробник повертає значення, що не є очікуваним об'єктом, то новий проміс сповнюється цим поверненим значенням. +- Якщо функція-обробник викидає помилку, то новий проміс відхиляється з викинутою помилкою. +- Якщо до початкового проміса не приєднано відповідного обробника, то новий проміс залагоджується в той самий стан, що й початковий проміс — тобто не маючи обробника відхилення, відхилений проміс залишається відхиленим з такою ж причиною. -Обробка відхиленого промісу в кожному `.then()` має наслідки далі всередині ланцюжка промісів. Інколи просто немає вибору, оскільки помилка має бути опрацьована одразу. В такому випадку ми повинні викинути помилку якогось типу, щоб зберегти вміст помилки далі всередині послідовності. З іншого боку, в разі відсутності нагальної потреби простіше віддати обробку помилки останній інструкції `.catch()` у ланцюжку. Фактично `.catch()` — це просто `.then()`, тільки без гнізда для функції успішного сповнення промісу. +Наприклад, у коді вище, якщо `myPromise` відхиляється, то викликається `handleRejectedA`, і якщо `handleRejectedA` завершиться нормально (без викидання помилки чи повернення відхиленого проміса), то проміс, повернений першим `then`, буде сповнений, а не залишиться відхиленим. Тому, якщо помилку треба обробити негайно, але потрібно зберегти стан помилки для використання в ланцюжку, необхідно викинути помилку певного типу в обробнику відхилення. З іншого боку, якщо немає негайної потреби, простіше покласти обробку помилок на останній обробник `catch()`. ```js myPromise @@ -99,23 +112,12 @@ myPromise }); ``` -> **Примітка:** Для швидшого виконання всі синхронні дії краще виконувати в межах одного обробника, інакше виконання всіх обробників у послідовності займе декілька тактів. +> [!NOTE] +> Для швидшого виконання всі синхронні дії краще виконувати в межах одного обробника, інакше виконання всіх обробників у послідовності займе декілька тактів. -Стан, з яким завершується проміс, визначає результат, яким "залагоджується" наступний проміс у послідовності. "Сповнений" стан позначає успішне завершення промісу, а стан "відхилено" — невдачу. Результат, повернутий кожним сповненим промісом у послідовності, передається далі до наступного `.then()`, натомість причина, з якої було відхилено якийсь із промісів, передається тільки до наступного обробника помилки у послідовності. - -Проміси в послідовності – вкладені один в одного, проте вони знімаються подібно до елементів стека. Перший проміс у послідовності загорнутий найглибше, проте він же буде першим, що витягнуть. - -```plain -(проміс D, (проміс C, (проміс B, (проміс A) ) ) ) -``` - -Якщо наступне значення `nextValue` — проміс, працює ефект динамічної заміни. Інструкція `return` змушує витягнути проміс зі стека, проте на його місце одразу вкладається проміс `nextValue`. У випадку, наведеному вище, припустімо, що `.then()`, пов'язаний з "промісом B", поверне "проміс X" як `nextValue`. Після цього картина вкладення матиме такий вигляд: - -```plain -(проміс D, (проміс C, (проміс X) ) ) -``` +JavaScript підтримує [чергу завдань](/uk/docs/Web/JavaScript/Event_loop). Щоразу, коли JavaScript бере завдання з черги, він виконує його до кінця. Завдання визначаються функцією-виконавцем конструктора `Promise()`, обробниками, переданими до `then`, або будь-яким API платформи, що повертає проміс. Проміси в ланцюжку представляють залежність між цими завданнями. Коли проміс залагоджується, відповідні обробники, пов'язані з ним, додаються до кінця черги завдань. -Один і той самий проміс може бути вкладений в декілька різних промісів. В прикладі нижче перехід `promiseA` в "залагоджений" стан змусить спрацювати обидва `.then()`. +Проміс може брати участь у більш ніж одному ланцюжку. У наступному коді сповнення `promiseA` призведе до того, що до черги завдань буде додано як `handleFulfilled1`, так і `handleFulfilled2`. Оскільки `handleFulfilled1` зареєстровано першим, він буде викликаний першим. ```js const promiseA = new Promise(myExecutorFunc); @@ -123,7 +125,7 @@ const promiseB = promiseA.then(handleFulfilled1, handleRejected1); const promiseC = promiseA.then(handleFulfilled2, handleRejected2); ``` -Можна прив'язати якусь дію до вже "залагодженого" промісу. В цьому випадку дію (якщо це допустимо) буде виконано при першій ліпшій асинхронній можливості. Зауважте, що проміси гарантовано асинхронні. Таким чином, дія для уже "залагодженого" промісу трапиться лише після того, як стек викликів буде очищено і мине мить таймера рушія. Цей ефект дуже схожий до результату виконання `setTimeout(action, 0)`. +Можна прив'язати якусь дію до вже залагодженого промісу. У цьому випадку дія додається в кінець черги завдань негайно і виконується, коли завершуються всі наявні завдання. У такий спосіб дія для вже "залагодженого" промісу відбудеться лише після завершення поточного синхронного коду та принаймні одного циклу обробки. Це створює гарантію того, що дії промісів – асинхронні. ```js const promiseA = new Promise((resolve, reject) => { @@ -184,7 +186,7 @@ Promise.resolve(aThenable); // Проміс сповнюється значен ## Статичні властивості -- {{jsxref("Promise/@@species", "Promise[@@species]")}} +- [`Promise[Symbol.species]`](/uk/docs/Web/JavaScript/Reference/Global_Objects/Promise/Symbol.species) - : Повертає конструктор, що використовується для створення значень, повернених з методів промісів. ## Статичні методи @@ -201,6 +203,8 @@ Promise.resolve(aThenable); // Проміс сповнюється значен - : Повертає новий об'єкт типу `Promise`, який відхиляється з переданою причиною. - {{jsxref("Promise.resolve()")}} - : Повертає об'єкт типу `Promise`, який вирішується з переданим результатом. Якщо результат є then-спроможним (має метод `then` - "відтак"), то повернений в результаті проміс "прослідкує" за цим then-спроможним і прийме його кінцевий стан. Інакше цей проміс буде просто сповнено переданим значенням. +- {{jsxref("Promise.try()")}} {{experimental_inline}} + - : Приймає функцію зворотного виклику будь-якого роду (що повертає значення або викидає помилку, синхронну або асинхронну) й загортає її результат у `Promise`. - {{jsxref("Promise.withResolvers()")}} - : Повертає об'єкт, що вміщає новий об'єкт `Promise` і дві функції для його розв'язання чи відхилення, що відповідають двом параметрам, переданим до виконувача конструктора {{jsxref("Promise/Promise", "Promise()")}}. @@ -210,8 +214,8 @@ Promise.resolve(aThenable); // Проміс сповнюється значен - {{jsxref("Object/constructor", "Promise.prototype.constructor")}} - : Функція-конструктор, що створила об'єкт-примірник. Для примірників `Promise` початковим значенням є конструктор {{jsxref("Promise/Promise", "Promise")}}. -- `Promise.prototype[@@toStringTag]` - - : Початкове значення властивості [`@@toStringTag`](/uk/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag) – рядок `"Promise"`. Ця властивість використовується в {{jsxref("Object.prototype.toString()")}}. +- `Promise.prototype[Symbol.toStringTag]` + - : Початкове значення властивості [`Symbol.toStringTag`](/uk/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag) – рядок `"Promise"`. Ця властивість використовується в {{jsxref("Object.prototype.toString()")}}. ## Методи примірника @@ -451,7 +455,8 @@ btn.addEventListener("click", testPromise); У наведеному вище прикладі текстовий вміст ` +``` + +Без цього `title` їм доведеться перейти до ` +Зверніть увагу на те, що за використання `srcdoc` будь-які відносні URL у вбудованому вмісті розв'язуються відносно URL вбудованої сторінки. Якщо потрібно використати якірні посилання, що вказують на місця у вбудованому вмісті, необхідно явно задати `about:srcdoc` як базовий URL. + +#### HTML + +```html-nolint +
+
Дев'ять хвилин тому jc написав:
+ +
``` -Без цього `title` їм доведеться перейти до `