Promise

Об'єкт Promise (зобов'язання, проміс) відображає успішне (або невдале) завершення якоїсь асинхронної операції та значення її результату.

Щоб дізнатися більше про те, як працюють проміси і як їх застосовувати, краще спершу прочитати застосування промісів.

Опис

Promise – це заміна для значення, яке, як правило, невідоме на момент, коли проміс створюється. Він дає змогу прив'язати обробники до результату успішного виконання чи до причини невдачі асинхронної операції. Це дає асинхронним методам змогу повертати значення схоже до того, як це роблять синхронні функції. Замість повернути одразу кінцеве значення метод повертає promise – зобов'язання надати це значення в якийсь момент у майбутньому.

Promise завжди знаходиться в одному з таких станів:

  • Очікування — pending: початковий стан, ні сповнений, ні відхилений.
  • Сповнений — fulfilled: означає, що операція була успішно завершена.
  • Відхилений — rejected: означає, що операція завершилася невдало.

Кінцевий стан промісу, який знаходиться в стані очікування, може бути або сповнений якимось результатом, або відхилений з якоїсь причини (через помилку). Коли відбувається якийсь із цих варіантів, викликаються відповідні обробники, задані методом then промісу. Якщо проміс уже було сповнено чи відхилено на момент, коли приєднується відповідний обробник, цей обробник буде одразу викликано. Таким чином не трапляється стан гонитви між асинхронною операцією завершення і приєднанням її обробників.

Про проміс кажуть, що він залагоджений, якщо він або сповнився, або відхилився, але не перебуває в стані очікування.

Діаграма, що показує, як стан промісу змінюється між очікуванням, сповненістю та відхиленістю за допомогою обробників then/catch. Проміс в стані очікування може стати або сповненим, або відхиленим. Якщо він був сповнений, то виконується обробник "при сповненні", або ж перший параметр метода then(), і продовжуються подальші асинхронні дії. Якщо проміс був відхилений, то виконується обробник помилки, або переданий як другий параметр метода then(), або як єдиний параметр метода catch().

Також можна зустріти використання з промісами терміну вирішений, – це означає, що проміс залагоджений або "замкнений" на відповідність кінцевому стану іншого проміса, і подальше його вирішення чи відхилення буде безрезультатним. Документ Стани та долі з оригінальної пропозиції промісів містить більше деталей щодо термінології промісів. У розмовній мові "вирішені" проміси нерідко еквівалентні до "сповнених", але, як це показано в "Станах та долях", вирішені проміси також можуть очікувати чи бути відхиленими. Наприклад:

new Promise((resolveOuter) => {
  resolveOuter(
    new Promise((resolveInner) => {
      setTimeout(resolveInner, 1000);
    }),
  );
});

Цей проміс є вже вирішеним на час створення (бо resolveOuter викликана синхронно), але він вирішений з іншим промісом, а тому не буде сповненим іще 1 секунду, поки не сповниться внутрішній проміс. На практиці "вирішення" нерідко виконується за лаштунками й не може відстежуватися, натомість сповнення й відхилення проміса – можуть.

[!NOTE] Декілька інших мов мають механізми лінивих та відкладених обчислень, котрі теж звуться "промісами", наприклад, Scheme. Проміси в JavaScript представляють процеси, що вже відбуваються, котрі можна зв'язати в ланцюжок за допомогою функцій зворотного виклику. Якщо треба ліниво обчислити вираз, слід розглянути можливість використання функції без аргументів, наприклад, f = () => expression, що породжує ліниво обчислений вираз, обчислити котрий можна за допомогою f().

Сам Promise не має протоколу першого класу для скасування, проте можливо, що вдасться безпосередньо скасувати асинхронну операцію, що за ним стоїть, зазвичай використовуючи AbortController.

Ланцюжки промісів

Методи промісів then(), catch() і finally() використовуються, щоб приєднати якусь наступну дію до промісу, який залагоджується. Метод .then() приймає до двох аргументів; перший — це функція зворотного виклику на випадок сповнення промісу, а другий — відповідно, на випадок його відхилення. Методи catch() і finally() за лаштунками викликають then() і роблять обробку помилок менш громіздкою. Наприклад, насправді catch() – це просто then() без передачі обробника сповнення. Оскільки ці методи повертають проміси, їхні виклики можна об'єднувати в ланцюжки. Наприклад:

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("foo");
  }, 300);
});

myPromise
  .then(handleFulfilledA, handleRejectedA)
  .then(handleFulfilledB, handleRejectedB)
  .then(handleFulfilledC, handleRejectedC);

Тут використовується наступна термінологія: початковий проміс – це той, на якому викликано then; новий проміс – це той, що повернений then. Два обробники, передані then, називаються обробником сповнення та обробником відхилення відповідно.

Стан залагодження початкового проміса визначає обробник, який буде виконано.

  • Якщо початковий проміс сповнено, то викликається обробник сповнення зі значенням сповнення.
  • Якщо початковий проміс відхилено, то викликається обробник відхилення з причиною відхилення.

Завершення обробника визначає стан залагодження нового проміса:

  • Якщо обробник повертає значення очікуваного об'єкта, то новий проміс залагоджується в той самий стан, що й повернутий проміс.
  • Якщо обробник повертає значення, що не є очікуваним об'єктом, то новий проміс сповнюється цим поверненим значенням.
  • Якщо обробник викидає помилку, то новий проміс відхиляється з викинутою помилкою.
  • Якщо до початкового проміса не приєднано відповідного обробника, то новий проміс залагоджується в той самий стан, що й початковий проміс — тобто не маючи обробника відхилення, відхилений проміс залишається відхиленим з такою ж причиною.

Наприклад, у коді вище, якщо myPromise відхиляється, то викликається handleRejectedA, і якщо handleRejectedA завершиться нормально (без викидання помилки чи повернення відхиленого проміса), то проміс, повернений першим then, буде сповнений, а не залишиться відхиленим. Тому, якщо помилку треба обробити негайно, але потрібно зберегти стан помилки для використання в ланцюжку, необхідно викинути помилку певного типу в обробнику відхилення. З іншого боку, якщо немає негайної потреби, можна покласти обробку помилок на останній обробник catch().

myPromise
  .then(handleFulfilledA)
  .then(handleFulfilledB)
  .then(handleFulfilledC)
  .catch(handleRejectedAny);

Реалізація послідовності промісів, записана із застосуванням стрілкових функцій як функцій зворотного виклику, може мати якийсь такий вигляд:

myPromise
  .then((value) => {
    return value + " іще ланка";
  })
  .then((value) => {
    return value + " і знову ланка";
  })
  .then((value) => {
    return value + " і знову";
  })
  .then((value) => {
    return value + " і знову";
  })
  .then((value) => {
    console.log(value);
  })
  .catch((err) => {
    console.log(err);
  });

[!NOTE] Для швидшого виконання всі синхронні дії краще виконувати в межах одного обробника, інакше виконання всіх обробників у послідовності займе декілька тактів.

JavaScript підтримує чергу завдань. Щоразу, коли JavaScript бере завдання з черги, він виконує його до кінця. Завдання визначаються функцією-виконавцем конструктора Promise(), обробниками, переданими до then, або будь-яким API платформи, що повертає проміс. Проміси в ланцюжку представляють залежність між цими завданнями. Коли проміс залагоджується, відповідні обробники, пов'язані з ним, додаються до кінця черги завдань.

Проміс може брати участь у більш ніж одному ланцюжку. У наступному коді сповнення promiseA призведе до того, що до черги завдань буде додано як handleFulfilled1, так і handleFulfilled2. Оскільки handleFulfilled1 зареєстровано першим, він буде викликаний першим.

const promiseA = new Promise(myExecutorFunc);
const promiseB = promiseA.then(handleFulfilled1, handleRejected1);
const promiseC = promiseA.then(handleFulfilled2, handleRejected2);

Можна прив'язати якусь дію до вже залагодженого промісу. У цьому випадку дія додається в кінець черги завдань негайно і виконується, коли завершуються всі наявні завдання. У такий спосіб дія для вже "залагодженого" промісу відбудеться лише після завершення поточного синхронного коду та принаймні одного циклу обробки. Це створює гарантію того, що дії промісів – асинхронні.

const promiseA = new Promise((resolve, reject) => {
  resolve(777);
});
// В цей момент "promiseA" уже залагоджено.
promiseA.then((val) =>
  console.log("асинхронний запис із таким значенням:", val),
);
console.log("запис одразу");

// виводить результати в такому порядку:
// запис одразу
// асинхронний запис із таким значенням: 777

Очікувані

Екосистема JavaScript мала декілька реалізацій промісів задовго до того, як вони стали частиною мови. Бувши всередині представленими по-різному, всі промісоподібні об'єкти щонайменше реалізовували інтерфейс очікуваного (thenables). Очікуваний об'єкт реалізовує метод .then(), котрий викликається з двома функціями зворотного виклику: одною на випадок сповнення промісу, однак на випадок відхилення. Проміси так само є очікуваними.

Щоб взаємодіяти з наявними реалізаціями Promise, мова дозволяє використання очікуваних об'єктів замість промісів. Наприклад, Promise.resolve вирішить не лише проміси, а й відстежить очікувані.

const aThenable = {
  then(onFulfilled, onRejected) {
    onFulfilled({
      // Очікуваний сповнюється іншим очікуваним
      then(onFulfilled, onRejected) {
        onFulfilled(42);
      },
    });
  },
};
Promise.resolve(aThenable); // Проміс сповнюється значенням 42

Рівночасність промісів

Клас Promise пропонує чотири методи для спрощення реалізації рівночасності асинхронних задач:

Promise.all()

Сповнюється, коли сповнюються всі проміси; відхиляється, коли відхиляється будь-який з промісів.

Promise.allSettled()

Сповнюється, коли залагоджуються всі проміси.

Promise.any()

Сповнюється, коли сповнюється будь-який з промісів; відхиляється, коли відхиляються всі проміси.

Promise.race()

Залагоджується, коли залагоджується будь-який з промісів. Інакше кажучи, сповнюється, коли сповнюється будь-який з промісів; відхиляється, коли відхиляється будь-який з промісів.

Усі ці методи приймають ітеровані колекції промісів (очікуваних, якщо точніше) і повертають новий проміс. Усі вони підтримують підкласи, а отже – їх можна викликати на підкласах Promise, а результат буде промісом з типом підкласу. Для цього конструктор підкласу мусить реалізувати таку само сигнатуру, як конструктор Promise(): приймання єдиної функції executor, що може бути викликана з функціями зворотного виклику resolve і reject як параметрами. Підклас також мусить мати статичний метод resolve, котрий можна викликати як Promise.resolve() для загортання значень у проміси.

Зверніть увагу, що JavaScript за своєю природою є однопотоковою мовою, тож у конкретну мить може виконуватися лише одна задача, хоч контроль може переходити від одного промісу до іншого, через що проміси здаються рівночасними. Паралельне виконання у JavaScript може бути досягнуто лише за допомогою тредів-воркерів.

Конструктор

Promise()

Створює новий об'єкт типу Promise. Здебільшого застосовується, щоб обгорнути функцію, яка ще не підтримує проміси.

Статичні властивості

Promise[Symbol.species]

Повертає конструктор, що використовується для створення значень, повернених з методів промісів.

Статичні методи

Promise.all()

Приймає на вхід ітеровану колекцію промісів і повертає єдиний Promise. Цей повернений проміс сповнюється, коли сповнюються всі проміси з вихідної колекції (включно з випадком, коли передана колекція – порожня), причому сповнюється масивом значень сповнення окремих промісів. Він відхиляється, коли відхиляється будь-який з промісів з вихідної колекції, причому значенням відхилення стає причина цього першого відхилення.

Promise.allSettled()

Приймає на вхід ітеровану колекцію промісів і повертає єдиний Promise. Цей повернений проміс сповнюється, коли залагоджуються всі проміси з вихідної колекції (включно з випадком, коли передана колекція – порожня), причому сповнюється масивом об'єктів, що описують результати кожного промісу.

Promise.any()

Приймає на вхід ітеровану колекцію промісів і повертає єдиний Promise. Цей повернений проміс сповнюється, коли сповнюється будь-який з промісів з вихідної колекції, причому сповнюється значенням сповнення цього першого сповненого промісу. Він відхиляється, коли відхиляються всі проміси з вихідної колекції (включно з випадком, коли передана колекція – порожня), причому значенням відхилення стає об'єкт AggregateError, що містить масив причин відхилення.

Promise.race()

Приймає на вхід ітеровану колекцію промісів і повертає єдиний Promise. Цей повернений проміс залагоджується зі станом, що відповідає остаточному станові першого промісу, що залагодився.

Promise.reject()

Повертає новий об'єкт типу Promise, який відхиляється з переданою причиною.

Promise.resolve()

Повертає об'єкт типу Promise, який вирішується з переданим результатом. Якщо результат є then-спроможним (має метод then - "відтак"), то повернений в результаті проміс "прослідкує" за цим then-спроможним і прийме його кінцевий стан. Інакше цей проміс буде просто сповнено переданим значенням.

Promise.try()

Приймає функцію зворотного виклику будь-якого роду (що повертає значення або викидає помилку, синхронну або асинхронну) й загортає її результат у Promise.

Promise.withResolvers()

Повертає об'єкт, що вміщає новий об'єкт Promise і дві функції для його розв'язання чи відхилення, що відповідають двом параметрам, переданим до виконувача конструктора Promise().

Властивості примірника

Ці властивості означені на Promise.prototype і є спільними для всіх примірників Promise.

Promise.prototype.constructor

Функція-конструктор, що створила об'єкт-примірник. Для примірників Promise початковим значенням є конструктор Promise.

Promise.prototype[Symbol.toStringTag]

Початкове значення властивості Symbol.toStringTag – рядок "Promise". Ця властивість використовується в Object.prototype.toString().

Методи примірника

Promise.prototype.catch() (перехопити)

Додає до промісу обробник відхилення і повертає новий проміс, який вирішується або з результатом виконання переданої функції зворотного виклику, або — якщо початковий проміс сповнився — значенням сповнення початкового проміса.

Promise.prototype.finally() (зрештою)

Додає до промісу обробник і повертає новий проміс, який вирішується, якщо початковий проміс теж вирішується. Обробник викликається, коли проміс залагоджується, незалежно від того, чи його було сповнено, чи відхилено.

Promise.prototype.then() (відтак)

Додає до промісу обробники виконання і відхилення, і повертає новий проміс. Цей новий проміс або залагоджується з результатом виклику відповідного обробника, або повертає значення, з яким було залагоджено попередній проміс (в разі, якщо відповідний обробник — onFulfilled або onRejected — не є функцією).

Приклади

Базовий приклад

const myFirstPromise = new Promise((resolve, reject) => {
  // Викликаємо resolve(...), коли те, що ми робимо асинхронно, завершилося успіхом, і reject(...), якщо операція була невдалою.
  // В цьому прикладі використаємо setTimeout(...) для симуляції асинхронного коду.
  // На практиці тут буде щось схоже на XHR чи API HTML.
  setTimeout(() => {
    resolve("Успіх!"); // Ура! Все пройшло добре!
  }, 250);
});

myFirstPromise.then((successMessage) => {
  // successMessage — це будь-яке значення, яке ми передаємо в функцію resolve(...) вище.
  // Воно не зобов'язане бути рядком, проте якщо це просто повідомлення про успіх — воно, ймовірно, буде рядком.
  console.log(`Ура! ${successMessage}`);
});

Приклад із різноманітними ситуаціями

Цей приклад показує різноманітні техніки застосування можливостей промісів і різні ситуації, які можуть трапитись. Для розуміння цього прикладу прокрутіть до кінця блоку з кодом і перегляньте ланцюжок промісів. Після початкового проміса може бути ланцюжок промісів. Він складається із викликів .then(), і зазвичай (проте на завжди) має єдиний .catch() наприкінці, після якого інколи може викликатись .finally(). В цьому прикладі ланцюжок промісів ініційовано за допомогою самописного new Promise(), проте на практиці послідовність промісів зазвичай починається викликом функції API (написаної кимось іншим), яка повертає проміс.

Функція tetheredGetNumber() в прикладі зображає генератор промісу, який викличе reject() або під час влаштування асинхронного виклику, або всередині функції зворотного виклику, або ж і там, і там. Функція promiseGetWord() ілюструє, як функція API може створювати та повертати проміс автономно.

Зауважте, що функція troubleWithGetNumber() завершується throw. Це вимушений крок, оскільки послідовність промісів у ES6 проходить через всі .then(), навіть після помилки. І без цього throw помилка буде здаватися "виправленою". Це зайвий клопіт, і через це зазвичай опускають onRejected у всій послідовності промісів .then() і просто залишають єдину onRejected всередині кінцевого catch().

Цей код може запускатися в середовищі NodeJS. Він буде більш зрозумілим, якщо переглянути помилки, які виникнуть у процесі виконання. Щоб збільшити кількість помилок, змініть значення threshold.

// Для експерименту з обробкою помилок значення "threshold" приводять до помилок випадковим чином
const THRESHOLD_A = 8; // можна використати 0, щоб гарантувати помилку

function tetheredGetNumber(resolve, reject) {
  setTimeout(() => {
    const randomInt = Date.now();
    const value = randomInt % 10;
    if (value < THRESHOLD_A) {
      resolve(value);
    } else {
      reject(`Завелике значення: ${value}`);
    }
  }, 500);
}
function determineParity(value) {
  const isOdd = value % 2 === 1;
  return { value, isOdd };
}

function troubleWithGetNumber(reason) {
  const err = new Error("Проблема з отриманням числа", { cause: reason });
  console.error(err);
  throw err;
}

function promiseGetWord(parityInfo) {
  return new Promise((resolve, reject) => {
    const { value, isOdd } = parityInfo;
    if (value >= THRESHOLD_A - 1) {
      reject(`Все ж завелике значення: ${value}`);
    } else {
      parityInfo.wordEvenOdd = isOdd ? "odd" : "even";
      resolve(parityInfo);
    }
  });
}

new Promise(tetheredGetNumber)
  .then(determineParity, troubleWithGetNumber)
  .then(promiseGetWord)
  .then((info) => {
    console.log(`Отримано: ${info.value}, ${info.wordEvenOdd}`);
    return info;
  })
  .catch((reason) => {
    if (reason.cause) {
      console.error("Маємо помилку, оброблену раніше");
    } else {
      console.error(`Проблема з promiseGetWord(): ${reason}`);
    }
  })
  .finally((info) => console.log("Все зроблено"));

Поглиблений приклад

Цей невеличкий приклад ілюструє сам механізм промісу. Метод testPromise() викликається під час кожного натискання елементу <button>. Це створює проміс, який за допомогою setTimeout() буде сповнено значенням кількості промісів (число, починаючи з 1) кожні 1-3 секунди (інтервал випадковий). Для створення промісів використано конструктор Promise().

Виконання промісів записується через функцію зворотного виклику, задану всередині p1.then(). Декілька записів, які виводяться в процесі роботи програми, показують, як синхронна частина методу відділена від асинхронного завершення промісу.

А якщо натиснути кнопку декілька разів протягом короткого проміжку часу, можна буде навіть побачити, як кілька різних промісів завершуються один за одним.

HTML

<button id="make-promise">Створити проміс!</button>
<div id="log"></div>

JavaScript

"use strict";
let promiseCount = 0;

function testPromise() {
  const thisPromiseCount = ++promiseCount;
  const log = document.getElementById("log");
  // початок
  log.insertAdjacentHTML("beforeend", `${thisPromiseCount}) Почалося<br>`);
  // Створюємо новий проміс: ми зобов'язуємося надати числовий лічильник цього промісу,
  // що починається з 1 (після очікування протягом 3 секунд)
  const p1 = new Promise((resolve, reject) => {
    // Функція, яка працює над виконанням промісу, викликається з можливістю
    // або вирішити, або відхилити проміс
    log.insertAdjacentHTML(
      "beforeend",
      `${thisPromiseCount}) Конструктор промісу<br>`,
    );
    // Це лише приклад того, як може виникнути асинхронність
    setTimeout(
      () => {
        // Сповнюємо проміс
        resolve(thisPromiseCount);
      },
      Math.random() * 2000 + 1000,
    );
  });

  // Оголошуємо через виклик then(), що саме потрібно зробити, коли проміс вирішується,
  // а за допомогою виклику catch() — що робити, якщо проміс відхилено
  p1.then((val) => {
    // Виводимо значення, яким сповнився проміс
    log.insertAdjacentHTML("beforeend", `${val}) Проміс сповнено<br>`);
  }).catch((reason) => {
    // Виводимо причину відхилення промісу
    console.log(`Тут оброблено відхилений проміс (${reason}).`);
  });
  // кінець
  log.insertAdjacentHTML(
    "beforeend",
    `${thisPromiseCount}) Проміс виконано<br>`,
  );
}

const btn = document.getElementById("make-promise");
btn.addEventListener("click", testPromise);

Результат

Завантаження зображення за допомогою XHR

Ще один приклад використання Promise, цього разу з завантаженням зображення за допомогою XMLHttpRequest, доступний на GitHub-репозиторії MDN js-examples. Також можна побачити його в дії. Кожний крок прокоментовано, що дає змогу докладно розглянути архітектуру промісів та XHR.

Відстежування поточного установчого об'єкта

Установчий об'єкт — це оточення, яке надає додаткову інформацію під час роботи JavaScript-коду. До нього входять царина (realm), карта модулів, а також специфічна для HTML інформація, наприклад, походження. Поточний установчий об'єкт постійно відстежується для гарантування того, що браузер знає, який із них застосовувати для даної ділянки користувацького коду.

Щоб краще це уявити, погляньмо ближче на те, яким чином царина може стати проблемою. Царину можна згрубша уявляти як глобальний об'єкт. Що особливого в царинах — так це те, що вони містять всю необхідну інформацію для виконання JavaScript-коду. Зокрема глобальні об'єкти, такі як Array та Error. Кожний установчий об'єкт має свою власну "копію" цих даних, і цю копію ні з ким не поділяє. Це може призвести до певної неочікуваної поведінки під час роботи з промісами. Щоб обійти такі проблеми, ми відстежуємо таку річ, як поточний установчий об'єкт. Він відповідає за інформацію, яка стосується контексту користувацького коду, відповідального за виклик певної функції.

Щоб краще це проілюструвати, подивімось на те, як вбудований в документ <iframe> спілкується зі своїм хазяїном. Оскільки всі веб-API мають на увазі поточний установчий об'єкт, наступний код буде працювати в усіх браузерах:

<!doctype html>
<!-- окрема царина в iframe -->
<iframe></iframe>
<script>
  // і також окрема царина тут
  const bound = frames[0].postMessage.bind(frames[0], "some data", "*");
  // bound – вбудована функція, тобто тут немає
  // користувацького коду на стеку, тож яка царина використовується?
  setTimeout(bound);
  // це все ж працює, оскільки ми використовуємо наймолодшу
  // царину (поточну) на стеку
</script>

Та сама ідея, але застосована до промісів. Якщо трошки змінити приклад вище, вийде отаке:

<!doctype html>
<!-- окрема царина в iframe -->
<iframe></iframe>
<script>
  // і також окрема царина тут
  const bound = frames[0].postMessage.bind(frames[0], "some data", "*");
  // bound – вбудована функція, тобто тут немає
  // користувацького коду на стеку, тож яка царина використовується?
  Promise.resolve(undefined).then(bound);
  // це все ж працює, оскільки ми використовуємо наймолодшу
  // царину (поточну) на стеку
</script>

Якщо змінити це таким чином, що <iframe> в документі слухатиме повідомлення, можна спостерігати ефект поточного установчого об'єкта:

<!-- y.html -->
<!doctype html>
<iframe src="x.html"></iframe>
<script>
  const bound = frames[0].postMessage.bind(frames[0], "some data", "*");
  Promise.resolve(undefined).then(bound);
</script>
<!-- x.html -->
<!doctype html>
<script>
  window.addEventListener(
    "message",
    (event) => {
      document.querySelector("#text").textContent = "hello";
      // Цей код спрацює лише у браузерах, які відстежують поточний установчий об'єкт
      console.log(event);
    },
    false,
  );
</script>

У наведеному вище прикладі текстовий вміст <iframe> буде оновлено лише у тому випадку, якщо поточний установчий об'єкт справді відстежується. Причина цього в тому, що без такого відстеження може трапитися надсилання повідомлення за допомогою не того середовища.

[!NOTE] Наразі відстежування поточної царини повністю реалізовано у Firefox і частково – в Chrome і Safari.

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
Promise
Chrome Full support 32
Edge Full support 12
Firefox Full support 29
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
Opera Android Full support 19
Safari on iOS Full support 8
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0
Promise() constructor Chrome Full support 32
Edge Full support 12
Firefox Full support 29
footnote
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
footnote
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
footnote
Opera Android Full support 19
Safari on iOS Full support 8
footnote
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0
footnote
all() Chrome Full support 32
Edge Full support 12
Firefox Full support 29
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
Opera Android Full support 19
Safari on iOS Full support 8
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0
allSettled() Chrome Full support 76
Edge Full support 79
Firefox Full support 71
Internet Explorer No support Ні
Opera Full support 63
Safari Full support 13
WebView Android Full support 76
Chrome Android Full support 76
Firefox for Android Full support 79
Opera Android Full support 54
Safari on iOS Full support 13
Samsung Internet Full support 12.0
Deno Full support 1.0
Node.js Full support 12.9.0
any Chrome Full support 85
Edge Full support 85
Firefox Full support 79
Internet Explorer No support Ні
Opera Full support 71
Safari Full support 14
WebView Android Full support 85
Chrome Android Full support 85
Firefox for Android Full support 79
Opera Android Full support 60
Safari on iOS Full support 14
Samsung Internet Full support 14.0
Deno Full support 1.2
Node.js Full support 15.0.0
catch() Chrome Full support 32
Edge Full support 12
Firefox Full support 29
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
Opera Android Full support 19
Safari on iOS Full support 8
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0
finally() Chrome Full support 63
Edge Full support 18
Firefox Full support 58
Internet Explorer No support Ні
Opera Full support 50
Safari Full support 11.1
WebView Android Full support 63
Chrome Android Full support 63
Firefox for Android Full support 58
Opera Android Full support 46
Safari on iOS Full support 11.3
Samsung Internet Full support 8.0
Deno Full support 1.0
Node.js Full support 10.0.0
Incumbent settings object tracking Chrome No support Ні
Edge No support Ні
Firefox Full support 50
Internet Explorer No support Ні
Opera No support Ні
Safari No support Ні
WebView Android No support Ні
Chrome Android No support Ні
Firefox for Android Full support 50
Opera Android No support Ні
Safari on iOS No support Ні
Samsung Internet No support Ні
Deno No support Ні
Node.js No support Ні
race() Chrome Full support 32
Edge Full support 12
Firefox Full support 29
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
Opera Android Full support 19
Safari on iOS Full support 8
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0
reject() Chrome Full support 32
Edge Full support 12
Firefox Full support 29
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
Opera Android Full support 19
Safari on iOS Full support 8
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0
resolve() Chrome Full support 32
Edge Full support 12
Firefox Full support 29
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
Opera Android Full support 19
Safari on iOS Full support 8
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0
then() Chrome Full support 32
Edge Full support 12
Firefox Full support 29
Internet Explorer No support Ні
Opera Full support 19
Safari Full support 8
WebView Android Full support 4.4.3
Chrome Android Full support 32
Firefox for Android Full support 29
Opera Android Full support 19
Safari on iOS Full support 8
Samsung Internet Full support 2.0
Deno Full support 1.0
Node.js Full support 0.12.0

Дивіться також