03. Promise Creation

Создать Promise можно одним из нескольких способов:

  • При помощи конструктора new Promise(executor);

  • Создать Promise с одним из установленных значений:

    • Promise.resolve();

    • Promise.reject().

  • Получить Promise вызвав одну из асинхронных операций, возвращающих Promise;

  • Конвертировать вызов функции с callback в функционально идентичный Promise.

new Promise(...) constructor

Promise-ы создаются при помощи конструктора new Promise(...):

new Promise(executor);
new Promise(function(resolve, reject) { ... });

Example:

function delay(ms) {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve, ms); // (A)
  });
}

// Using delay():
delay(5000).then(function() {
  // (B)
  console.log("5 seconds have passed!");
});

Executor

Передаваемый в конструктор Promise параметр называется executor.

Executor - это функция с двумя параметрами resolve и reject. Первый аргумент используется для успешной установки Promise, тогда как второй для неуспешной.

  • Если вычисление прошло успешно, то результат посылается при помощи resolve(value)

  • Если вычисление завершилось аварийно, то клиент Promise уведомляется об ошибке при помощи reject(error).

Например:

const promise = new Promise((resolve, reject) => { // (A)
    ···
    if (···) {
        resolve(value); // success
    } else {
        reject(reason); // failure
    }
});

После вызова resolve/reject Promise переходит в одно из установленных состояний – с результатом (resolve), или ошибкой (reject):

const promise = new Promise((resolve, reject) => {
  // через 1 секунду готов результат: result
  setTimeout(() => resolve("result"), 1000);

  // через 2 секунды — reject с ошибкой, он будет проигнорирован
  setTimeout(() => reject(new Error("ignored")), 2000);
});

promise.then(
  result => console.log(`Fulfilled: ${result}`), // сработает
  error => console.log(`Rejected: ${error}`) // не сработает
);

It’s important to note that only the first call made to either of these methods will have an impact – once a promise is settled, it’s result can’t change. The example below creates a promise that’s fulfilled in the allowed time or rejected after a generous timeout:

function resolveUnderThreeSeconds(delay) {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve, delay);
    setTimeout(reject, 3000);
  });
}
resolveUnderThreeSeconds(2000); // resolves!
resolveUnderThreeSeconds(7000); // fulfillment took so long, it was rejected.

Если внутри executor было выброшено исключение, то это аналогично выражению reject(new Error(...)):

const p = new Promise((resolve, reject) => {
  // Same as reject(new Error("o_O"))
  throw new Error("o_O");
});

p.catch(console.log); // Error: o_O

Executor выполняется синхронно вместе с созданием Promise, но любые обработчики всегда выполняются асинхронно.

Если ни reject ни resolve не были вызваны, то обработчики на Promise так и не сработают и Promise будет когда-нибудь собран сборщиком мусора.

Settled Promise

Создать Promise c определенным состоянием можно при помощи одного из следующих методов:

  • Promise.resolve(value|promise|thenable) - создает Promise с состоянием fulfilled и с установленным значением.

  • Promise.reject(value|promise|thenable) - создает Promise с состоянием rejected и с установленным значением.

// Using the static Promise.resolve method:
Promise.resolve("Success").then(
  value => console.log(value), // "Success"
  value => {
    // not called
  }
);

// Using the Promise.reject method:
Promise.reject(new Error("fail")).then(
  error => {
    // not called
  },
  error => console.log(error) // Stacktrace,
);

Promise.resolve

The Promise.resolve(value) method returns a Promise object that is resolved with the given value. If the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state; if the value was a promise, that object becomes the result of the call to Promise.resolve; otherwise the returned promise will be fulfilled with the value.

const original = Promise.resolve(33);
const cast = Promise.resolve(original);

cast.then(value => {
  console.log(`value: ${value}`);
});

console.log(`original === cast ? ${original === cast}`);
// original === cast ? true
// value: 33

Promise.resolve is good for wrapping synchronous code:

Promise.resolve().then(function() {
  if (somethingIsNotRight()) {
    throw new Error("I will be rejected asynchronously!");
  } else {
    return "This string will be resolved asynchronously!";
  }
});

util.promisify()

Node 8 has a new utility function: util.promisify(). It converts a callback-based function to a Promise-based one.

const { promisify } = require("util");
const fs = require("fs");

const readFileAsync = promisify(fs.readFile); // (A)

readFileAsync("package.json", { encoding: "utf8" })
  .then(text => {
    console.log("CONTENT:", text);
  })
  .catch(err => {
    console.log("ERROR:", err);
  });

Last updated