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 15885f322c..a281e7fdd6 100644 --- a/files/uk/web/javascript/reference/global_objects/promise/index.md +++ b/files/uk/web/javascript/reference/global_objects/promise/index.md @@ -16,35 +16,46 @@ browser-compat: javascript.builtins.Promise Об'єкт **`Promise`** (зобов‘язання, проміс) відображає успішне (або невдале) завершення якоїсь асинхронної операції та значення її результату. -{{AvailableInWorkers}} - -Щоб взнати більше про те, як працюють проміси і як їх застосовувати, радимо спершу прочитати [застосування промісів](/uk/docs/Web/JavaScript/Guide/Using_promises). +Щоб дізнатися більше про те, як працюють проміси і як їх застосовувати, краще спершу прочитати [застосування промісів](/uk/docs/Web/JavaScript/Guide/Using_promises). ## Опис -**`Promise`** — це заміна для значення, яке, як правило, невідоме на момент, коли проміс створюється. Він дає змогу прив'язати обробники до результату успішного виконання чи до причини невдачі асинхронної операції. Це дає можливість асинхронним методам повертати значення схоже до того, як це роблять синхронні функції. Замість повернути одразу кінцеве значення метод повертає _promise - зобов'язання_ надати це значення в якийсь момент у майбутньому. +**`Promise`** – це заміна для значення, яке, як правило, невідоме на момент, коли проміс створюється. Він дає змогу прив'язати обробники до результату успішного виконання чи до причини невдачі асинхронної операції. Це дає асинхронним методам змогу повертати значення схоже до того, як це роблять синхронні функції. Замість повернути одразу кінцеве значення метод повертає _promise - зобов'язання_ надати це значення в якийсь момент у майбутньому. `Promise` завжди знаходиться в одному з таких станів: - Очікування — _pending_: початковий стан, ні сповнений, ні відхилений. -- Виконаний — _fulfilled_: означає, що операція була успішно завершена. +- Сповнений — _fulfilled_: означає, що операція була успішно завершена. - Відхилений — _rejected_: означає, що операція завершилася невдало. -Проміс, який знаходиться в стані очікування, можна або _сповнити_ якимось результатом, або _відхилити_ з якоїсь причини (помилки). Коли відбувається якийсь із цих варіантів, викликаються відповідні обробники, задані методом `then` промісу. Якщо проміс уже було сповнено чи відхилено на момент, коли приєднується відповідний обробник, його буде одразу викликано. Таким чином не відбувається стану гонитви між асинхронною операцією завершення і приєднанням її обробників. +_Кінцевий стан_ промісу, який знаходиться в стані очікування, може бути або _сповнений_ якимось результатом, або _відхилений_ з якоїсь причини (через помилку). +Коли відбувається якийсь із цих варіантів, викликаються відповідні обробники, задані методом `then` промісу. Якщо проміс уже було сповнено чи відхилено на момент, коли приєднується відповідний обробник, цей обробник буде одразу викликано. Таким чином не трапляється стан гонитви між асинхронною операцією завершення і приєднанням її обробників. -Оскільки методи `{{JSxRef("Promise.then", "Promise.prototype.then()")}}` і `{{JSxRef("Promise.catch", "Promise.prototype.catch()")}}` також повертають проміси, їх можна зв'язувати у ланцюжок. +Про проміс кажуть, що він _залагоджений_, якщо він або сповнився, або відхилився, але не перебуває в стані очікування. ![](promises.png) -> **Примітка:** Декілька інших мов також мають механізми для лінивого обчислення і відкладених обрахунків, які також називаються "promises", зокрема Scheme. Проміси в JavaScript позначають процеси, які вже відбуваються, і які можна об'єднати у ланцюжок з функціями зворотного виклику. Якщо вас цікавить саме ліниве обчислення значення якогось виразу, зверніть увагу на [стрілкову функцію](/uk/docs/Web/JavaScript/Reference/Functions/Arrow_functions) без аргументів: `f = () => вираз` задає вираз для лінивого обчислення, а `f()` безпосередньо обчислює його. +Також можна зустріти використання з промісами терміну _вирішений_, – це означає, що проміс залагоджений або "замкнений" на відповідність кінцевому стану іншого проміса, і подальше його вирішення чи відхилення буде безрезультатним. Документ [Стани та долі (англ.)](https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md) з оригінальної пропозиції промісів містить більше деталей щодо термінології промісів. У розмовній мові "вирішені" проміси нерідко еквівалентні до "сповнених", але, як це показано в "Станах та долях", вирішені проміси також можуть очікувати чи бути відхиленими. Наприклад: + +```js +new Promise((resolveOuter) => { + resolveOuter( + new Promise((resolveInner) => { + setTimeout(resolveInner, 1000); + }), + ); +}); +``` + +Цей проміс є вже _вирішеним_ на час створення (бо `resolveOuter` викликана синхронно), але він вирішений з іншим промісом, а тому не буде _сповненим_ іще 1 секунду, поки не сповниться внутрішній проміс. На практиці "вирішення" нерідко виконується за лаштунками й не може відстежуватися, натомість сповнення й відхилення проміса – можуть. -> **Примітка:** Проміс вважається _settled — залагодженим_ якщо він або сповнений, або відхилений, але не в стані очікування. Також зустрічається термін _вирішений — resolved_ — це означає, що проміс або залагоджений, або "замкнений" на стан іншого промісу. Стаття [стани й долі (англ.)](https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md) містить більше деталей про термінологію промісів. +> **Примітка:** Декілька інших мов мають механізми лінивих та відкладених обчислень, котрі теж звуться "промісами", наприклад, Scheme. Проміси в JavaScript представляють процеси, що вже відбуваються, котрі можна зв‘язати в ланцюжок за допомогою функцій зворотного виклику. Якщо треба ліниво обчислити вираз, слід розглянути можливість використання функції без аргументів, наприклад, `f = () => expression`, що породжує ліниво обчислений вираз, обчислити котрий можна за допомогою `f()`. ### Ланцюжки промісів -Методи `{{jsxref("Promise.prototype.then()")}}`, `{{jsxref("Promise.prototype.catch()")}}` і `{{jsxref("Promise.prototype.finally()")}}` використовуються, щоб приєднати якусь наступну дію до промісу, який залагоджується. +Методи `{{jsxref("Promise.prototype.then()")}}`, `{{jsxref("Promise.prototype.catch()")}}` і `{{jsxref("Promise.prototype.finally()")}}` використовуються, щоб приєднати якусь наступну дію до промісу, який залагоджується. Оскільки методи `{{JSxRef("Promise.then", "Promise.prototype.then()")}}` та `{{JSxRef("Promise.catch", "Promise.prototype.catch()")}}` повертають проміси, їх виклики можна об‘єднати в ланцюжок. -Метод `.then()` приймає до двох аргументів; перший — це функція зворотного виклику для вирішення промісу, а другий — відповідно, функція для його відхилення. Кожний `.then()` повертає новостворений об'єкт промісу, який далі може (необов'язково) використовуватися для нарощування ланцюжка викликів, як от: +Метод `.then()` приймає до двох аргументів; перший — це функція зворотного виклику для сповнення промісу, а другий — відповідно, функція для його відхилення. Кожний `.then()` повертає новостворений об'єкт промісу, який далі може (необов'язково) використовуватися для нарощування ланцюжка викликів, як от: ```js const myPromise = new Promise((resolve, reject) => { @@ -54,20 +65,20 @@ const myPromise = new Promise((resolve, reject) => { }); myPromise - .then(handleResolvedA, handleRejectedA) - .then(handleResolvedB, handleRejectedB) - .then(handleResolvedC, handleRejectedC); + .then(handleFulfilledA, handleRejectedA) + .then(handleFulfilledB, handleRejectedB) + .then(handleFulfilledC, handleRejectedC); ``` Процес продовжується до наступної ланки ланцюжка, навіть якщо у наступний `.then()` не було передано функцію зворотного виклику, яка б повернула наступний проміс. Таким чином, ланцюжок може спокійно оминати кожний виклик функції _відхилення_ аж до останнього `.catch()`. -Обробка відхиленого промісу в кожному `.then()` має наслідки далі всередині ланцюжка промісів. Інколи просто немає вибору, оскільки помилка має бути опрацьована одразу. В такому випадку ми повинні викинути помилку якогось типу, щоб зберегти вміст помилки далі всередині послідовності. З іншого боку, в разі відсутності нагальної потреби простіше віддати обробку помилки останній інструкції `.catch()` у ланцюжку. Фактично `.catch()` — це просто `.then()`, тільки без гнізда для функції успішного вирішення промісу. +Обробка відхиленого промісу в кожному `.then()` має наслідки далі всередині ланцюжка промісів. Інколи просто немає вибору, оскільки помилка має бути опрацьована одразу. В такому випадку ми повинні викинути помилку якогось типу, щоб зберегти вміст помилки далі всередині послідовності. З іншого боку, в разі відсутності нагальної потреби простіше віддати обробку помилки останній інструкції `.catch()` у ланцюжку. Фактично `.catch()` — це просто `.then()`, тільки без гнізда для функції успішного сповнення промісу. ```js myPromise - .then(handleResolvedA) - .then(handleResolvedB) - .then(handleResolvedC) + .then(handleFulfilledA) + .then(handleFulfilledB) + .then(handleFulfilledC) .catch(handleRejectedAny); ``` @@ -95,15 +106,15 @@ myPromise }); ``` -Стан, з яким завершується проміс, визначає результат, яким "залагоджується" наступний проміс у послідовності. "Вирішений " стан позначає успішне завершення промісу, а стан "відхилено" — невдачу. Результат, повернутий кожним промісом у послідовності, передається далі до наступного `.then()`, натомість причина, з якої було відхилено якийсь із промісів, передається тільки до наступного обробника помилки у послідовності. +Стан, з яким завершується проміс, визначає результат, яким "залагоджується" наступний проміс у послідовності. "Сповнений" стан позначає успішне завершення промісу, а стан "відхилено" — невдачу. Результат, повернутий кожним сповненим промісом у послідовності, передається далі до наступного `.then()`, натомість причина, з якої було відхилено якийсь із промісів, передається тільки до наступного обробника помилки у послідовності. -Проміси в послідовності наче вкладені один в одного, як шари в цибулині, проте вони витягуються схоже до вершини стеку. Перший проміс у послідовності загорнутий найглибше, проте він же і буде першим, який витягнуть. +Проміси в послідовності наче вкладені один в одного, як шари в цибулині, проте вони знімаються, подібно до верхівки стека. Перший проміс у послідовності загорнутий найглибше, проте він же і буде першим, який витягнуть. ```plain (проміс D, (проміс C, (проміс B, (проміс A) ) ) ) ``` -Якщо наступне значення `nextValue` — проміс, працює ефект динамічної перестановки. Інструкція `return` змушує витягнути проміс зі стека, проте на його місце одразу вкладається проміс `nextValue`. У випадку, наведеному вище, припустімо, що `.then()` пов'язаний з "промісом B" поверне "проміс X" як `nextValue`. Після цього картина вкладення матиме такий вигляд: +Якщо наступне значення `nextValue` — проміс, працює ефект динамічної заміни. Інструкція `return` змушує витягнути проміс зі стека, проте на його місце одразу вкладається проміс `nextValue`. У випадку, наведеному вище, припустімо, що `.then()`, пов'язаний з "промісом B", поверне "проміс X" як `nextValue`. Після цього картина вкладення матиме такий вигляд: ```plain (проміс D, (проміс C, (проміс X) ) ) @@ -134,6 +145,26 @@ console.log('запис одразу'); // асинхронний запис із таким значенням: 777 ``` +### Очікувані + +Екосистема JavaScript мала декілька реалізацій промісів задовго до того, як вони стали частиною мови. Бувши всередині представленими по-різному, всі промісоподібні об‘єкти щонайменше реалізовували інтерфейс _очікуваного_ (thenables). Очікуваний об‘єкт реалізовує метод [`.then()`](/uk/docs/Web/JavaScript/Reference/Global_Objects/Promise/then), котрий викликається з двома функціями зворотного виклику: одною на випадок сповнення промісу, однак на випадок відхилення. Проміси так само є очікуваними. + +Щоб взаємодіяти з наявними реалізаціями Promise, мова дозволяє використання очікуваних об'єктів замість промісів. Наприклад, [`Promise.resolve`](/uk/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve) вирішить не лише проміси, а й відстежить очікувані. + +```js +const aThenable = { + then(onFulfilled, onRejected) { + onFulfilled({ + // Очікуваний сповнюється іншим очікуваним + then(onFulfilled, onRejected) { + onFulfilled(42); + }, + }); + }, +}; +Promise.resolve(aThenable); // Проміс сповнюється значенням 42 +``` + ### Відстежування поточного установчого об'єкта Установчий об'єкт — це [оточення (англ.)](https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object), яке надає додаткову інформацію під час роботи JavaScript-коду. До нього входять область (realm), карта модулів, а також специфічна для HTML інформація, наприклад, `origin`. Поточний установчий об'єкт постійно відстежується для гарантування того, що браузер знає, який із них застосовувати для даної ділянки користувацького коду. @@ -215,7 +246,7 @@ console.log('запис одразу'); - {{JSxRef("Promise.all", "Promise.all(iterable)")}} - - : Чекає, поки всі проміси вирішаться, або поки хоча б один із них буде відхилено. + - : Чекає, поки всі проміси сповняться, або поки хоча б один із них буде відхилено. Якщо повернений в результаті виклику цього методу проміс вирішується, він передає збірний масив результатів вирішення всіх переданих спочатку промісів. Порядок результатів у масиві збігається з порядком початкових промісів у масиві. @@ -223,19 +254,19 @@ console.log('запис одразу'); - {{JSxRef("Promise.allSettled", "Promise.allSettled(iterable)")}} - - : Чекає, поки всі проміси буде залагоджено (кожний може або вирішитись, або відхилитись). + - : Чекає, поки всі проміси буде залагоджено (кожний може або сповнитись, або відхилитись). - Повертає проміс, який вирішується після того, як всі передані в нього проміси або сповнюються, або відхиляються. В цей повернений проміс передається масив об'єктів відповідно до результатів кожного з початкових промісів. + Повертає проміс, який сповнюється після того, як всі передані в нього проміси або сповнюються, або відхиляються. В цей повернений проміс передається масив об'єктів відповідно до результатів кожного з початкових промісів. - {{JSxRef("Promise.any", "Promise.any(iterable)")}} - - : Приймає масив об'єктів типу Promise. Як тільки хоча б один із цих промісів сповнюється, повертає єдиний проміс, який вирішується із результатом роботи сповненого промісу з масиву. + - : Приймає масив об'єктів типу Promise. Як тільки хоча б один із цих промісів сповнюється, повертає єдиний проміс, який сповнюється результатом роботи сповненого промісу з масиву. - {{JSxRef("Promise.race", "Promise.race(iterable)")}} - : Чекає, поки будь-який із переданих промісів або сповнюється, або відхиляється. - Якщо проміс в результаті вирішується, то його значення вирішення – значення першого промісу в наборі, який вирішився. + Якщо проміс в результаті сповнюється, то його значення сповнення – значення першого промісу в наборі, який сповнився. Якщо він відхиляється, він відхиляється з причиною з першого промісу, який був відхилений. @@ -247,7 +278,7 @@ console.log('запис одразу'); Загалом, якщо наперед не відомо, чи результат є промісом, чи ні, краще просто викликати {{JSxRef("Promise.resolve", "Promise.resolve(value)")}} на ньому і працювати з результатом такого виклику далі як з промісом. -## Методи екземпляру +## Методи примірника Ознайомтесь із [Настановами з мікрозавдань](/uk/docs/Web/API/HTML_DOM_API/Microtask_guide), щоб дізнатись більше про те, як ці методи працюють із чергою та сервісами мікрозавдань. @@ -285,7 +316,7 @@ myFirstPromise.then((successMessage) => { Функція `tetheredGetNumber()` в прикладі зображає генератор промісу, який викличе `reject()` або під час влаштування асинхронного виклику, або всередині функції зворотного виклику, або ж і там, і там. Функція `promiseGetWord()` ілюструє, як функція API може створювати та повертати проміс автономно. -Зауважте, що функція `troubleWithGetNumber()` завершується `throw()`. Це вимушений крок, оскільки послідовність промісів у ES6 проходить через всі `.then()`, навіть після помилки. І без цього "throw()" помилка буде здаватися "виправленою". Це зайвий клопіт, і через це зазвичай опускають `rejectionFunc` у всій послідовності промісів `.then()` і просто залишають єдину `rejectionFunc` всередині кінцевого `catch()`. Альтернативно можна викинути особливе значення (в цьому випадку "-999", проте більш правильно мати власний тип об'єкту Error). +Зауважте, що функція `troubleWithGetNumber()` завершується `throw()`. Це вимушений крок, оскільки послідовність промісів у ES6 проходить через всі `.then()`, навіть після помилки. І без цього "throw()" помилка буде здаватися "виправленою". Це зайвий клопіт, і через це зазвичай опускають `rejectionFunc` у всій послідовності промісів `.then()` і просто залишають єдину `rejectionFunc` всередині кінцевого `catch()`. Альтернативно можна викинути особливе значення (в цьому випадку "-999", проте більш правильно мати власний тип об‘єкта Error). Цей код може запускатися в середовищі NodeJS. Він буде більш зрозумілим, якщо переглянути помилки, які виникнуть у процесі виконання. Щоб збільшити кількість помилок, змініть значення `threshold`. @@ -431,7 +462,7 @@ if ('Promise' in window) { #### Результат -{{EmbedLiveSample("Advanced_Example", "500", "200")}} +{{EmbedLiveSample("pohlyblenyi-pryklad", "500", "200")}} ### Завантаження зображення за допомогою XHR diff --git a/uk_spelling_additions.txt b/uk_spelling_additions.txt index 6906059424..27fbde065d 100644 --- a/uk_spelling_additions.txt +++ b/uk_spelling_additions.txt @@ -90,6 +90,7 @@ проміси промісів промісом +промісоподібні промісу рендериться рядки-об'єкти