Поиск…


Синтаксис

  • новая функция Promise (/ * executor: * / function (разрешение, отклонение) {})
  • prom.then (onFulfilled [, onRejected])
  • promise.catch (onRejected)
  • Promise.resolve (разрешение)
  • Promise.reject (причина)
  • Promise.all (итерация)
  • Promise.race (итерация)

замечания

Обещания являются частью спецификации ECMAScript 2015, а поддержка браузера ограничена, а 88% браузеров по всему миру поддерживают ее по состоянию на июль 2017 года. В следующей таблице представлен обзор ранних версий браузера, которые обеспечивают поддержку обещаний.

Хром край Fire Fox Internet Explorer опера опера мини Сафари iOS Safari
32 12 27 Икс 19 Икс 7,1 8

В средах, которые их не поддерживают, Promise может быть многозаполненным. Сторонние библиотеки могут также предоставлять расширенные функции, такие как автоматическое «обещание» функций обратного вызова или дополнительные методы, такие как progress также известный как notify .

Веб-сайт Promises / A + предоставляет список версий, совместимых с 1.0 и 1.1 . Promise callbacks, основанные на стандарте A +, всегда выполняются асинхронно в виде микротоков в цикле событий .

Цепочная цепочка

then метод обещания возвращает новое обещание.

const promise = new Promise(resolve => setTimeout(resolve, 5000));

promise
    // 5 seconds later
    .then(() => 2)
    // returning a value from a then callback will cause
    // the new promise to resolve with this value
    .then(value => { /* value === 2 */ });

Возвращение Promise с then обратного вызова добавит его в цепочку обещаний.

function wait(millis) {
    return new Promise(resolve => setTimeout(resolve, millis));
}

const p = wait(5000).then(() => wait(4000)).then(() => wait(1000));
p.then(() => { /* 10 seconds have passed */ });

catch позволяет отказаться от обещания восстановить, подобно тому, как работает catch в заявлении try / catch . Любая цепочка then того, как catch , выполнит свой обработчик разрешений, используя значение, разрешенное из catch .

const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console));  // outputs "oh yes"

Если в середине цепи нет обработчиков catch или reject , catch в конце будет захватывать любое отклонение в цепочке:

p.catch(() => Promise.reject('oh yes'))
  .then(console.log.bind(console))      // won't be called
  .catch(console.error.bind(console));  // outputs "oh yes"

В некоторых случаях вы можете «разветвить» выполнение функций. Вы можете сделать это, возвратив различные обещания от функции в зависимости от состояния. Позже в коде вы можете объединить все эти ветви в один, чтобы вызвать на них другие функции и / или обрабатывать все ошибки в одном месте.

promise
    .then(result => {          
        if (result.condition) {
            return handlerFn1() 
                .then(handlerFn2);
        } else if (result.condition2) {
            return handlerFn3()
                .then(handlerFn4);
        } else {
            throw new Error("Invalid result");
        }
    })
    .then(handlerFn5)
    .catch(err => {
        console.error(err);
    });

Таким образом, порядок выполнения функций выглядит так:

promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
         |                            ^
         V                            |
         -> handlerFn3 -> handlerFn4 -^            

Единственный catch получит ошибку в зависимости от того, какая ветка может произойти.

Вступление

Объект Promise представляет собой операцию, которая произвела или в конечном итоге произведет значение. Обещания обеспечивают надежный способ обертывания (возможно, ожидающего) результата асинхронной работы, смягчая проблему глубоко вложенных обратных вызовов (известный как « callback hell »).

Государства и поток управления

Обещание может быть в одном из трех состояний:

  • Ожидание - основная операция еще не завершена, и обещание ожидает выполнения.
  • выполнено - операция завершена, и обещание исполнено со значением . Это аналогично возврату значения из синхронной функции.
  • отклонено - во время операции произошла ошибка, и обещание отклонено по причине . Это аналогично ошибке в синхронной функции.

Обещание считается урегулированным (или разрешенным ), когда оно либо выполняется, либо отклонено. Как только обещание будет урегулировано, оно станет неизменным, и его состояние не может измениться. Методы then и catch для обещания могут использоваться для присоединения обратных вызовов, которые выполняются при его разрешении. Эти обратные вызовы вызываются с указанием значения выполнения и причины отклонения, соответственно.

Схема последовательности обещаний

пример

const promise = new Promise((resolve, reject) => {
    // Perform some work (possibly asynchronous)
    // ...

    if (/* Work has successfully finished and produced "value" */) {
        resolve(value);
    } else {
        // Something went wrong because of "reason"
        // The reason is traditionally an Error object, although
        // this is not required or enforced.
        let reason = new Error(message);
        reject(reason);

        // Throwing an error also rejects the promise.
        throw reason;
    }
});

Методы then и catch могут использоваться для присоединения обратных вызовов выполнения и отказа:

promise.then(value => {
    // Work has completed successfully,
    // promise has been fulfilled with "value"
}).catch(reason => {
    // Something went wrong,
    // promise has been rejected with "reason"
});

Примечание. Призыв к обещанию. promise.then(...) и promise.catch(...) по одному и тому же обещанию может привести к Uncaught exception in Promise если возникает ошибка при выполнении обещания или внутри одного из обратных вызовов, поэтому предпочтительным способом было бы присоединение следующего слушателя к обещанию, возвращенному предыдущим then / catch .

В качестве альтернативы, оба обратных вызовов могут быть присоединены в одном вызове , then :

promise.then(onFulfilled, onRejected);

Прикрепление обратных вызовов к обещанию, которое уже было разрешено, немедленно помещает их в очередь микрозадач , и они будут вызваны «как можно скорее» (т.е. сразу после исполняемого сценария). Нет необходимости проверять состояние обещания перед подключением обратных вызовов, в отличие от многих других событий-излучающих реализаций.


Демо-версия

Вызов функции задержки

Метод setTimeout() вызывает функцию или вычисляет выражение после заданного количества миллисекунд. Это также тривиальный способ достижения асинхронной операции.

В этом примере вызов функции wait разрешает обещание после времени, указанного в качестве первого аргумента:

function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));  
}

wait(5000).then(() => { 
    console.log('5 seconds have passed...');
});

Ожидание множества одновременных обещаний

Статический метод Promise.all() принимает итеративный (например, Array ) обещаний и возвращает новое обещание, которое разрешает, когда все обещания в iterable разрешат, или отклоняет, если хотя бы одно из обещаний в итерабеле отклонено.

// wait "millis" ms, then resolve with "value"
function resolve(value, milliseconds) {
    return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}

// wait "millis" ms, then reject with "reason"
function reject(reason, milliseconds) {
    return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    resolve(3, 7000)    
]).then(values => console.log(values)); // outputs "[1, 2, 3]" after 7 seconds.

Promise.all([
    resolve(1, 5000),
    reject('Error!', 6000),
    resolve(2, 7000)
]).then(values => console.log(values)) // does not output anything
.catch(reason => console.log(reason)); // outputs "Error!" after 6 seconds.

Нобелевские значения в итерабеле «многозначны» .

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    { hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds

Назначение деструкции может помочь получить результаты из нескольких обещаний.

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
    console.log(result1);
    console.log(result2);
    console.log(result3);
});

Ожидание первого из нескольких параллельных обещаний

Статический метод Promise.race() принимает итерабельность обещаний и возвращает новое обещание, которое разрешает или отклоняет, как только первое из обещаний в итерабеле разрешено или отклонено.

// wait "milliseconds" milliseconds, then resolve with "value"
function resolve(value, milliseconds) {
    return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}

// wait "milliseconds" milliseconds, then reject with "reason"
function reject(reason, milliseconds) {
    return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}

Promise.race([
    resolve(1, 5000),
    resolve(2, 3000),
    resolve(3, 1000)
])
.then(value => console.log(value)); // outputs "3" after 1 second.


Promise.race([
    reject(new Error('bad things!'), 1000),
    resolve(2, 2000)
])
.then(value => console.log(value)) // does not output anything
.catch(error => console.log(error.message)); // outputs "bad things!" after 1 second

Значения «Promisifying»

Статический метод Promise.resolve можно использовать для переноса значений в обещания.

let resolved = Promise.resolve(2);
resolved.then(value => {
    // immediately invoked
    // value === 2
});

Если value уже является обещанием, Promise.resolve просто переделывает его.

let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
    // 1 second has passed
    // value === 2
});

Фактически, value может быть любым «thenable» (объект, определяющий метод then который работает достаточно, как обещание, совместимое со спецификацией). Это позволяет Promise.resolve конвертировать ненадежные сторонние объекты в доверенные Promise.resolve обещания.

let resolved = Promise.resolve({
    then(onResolved) {
        onResolved(2);
    }
});
resolved.then(value => {
    // immediately invoked
    // value === 2
});

Статический метод Promise.reject возвращает обещание, которое немедленно отклоняется по данной reason .

let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
    // immediately invoked
    // reason === "Oops!"
});

Функции «Promisifying» с обратными вызовами

Учитывая функцию, которая принимает обратный вызов в стиле узла,

fooFn(options, function callback(err, result) { ... });

вы можете обещать его (преобразовать его в функцию, основанную на обещании) следующим образом:

function promiseFooFn(options) {
    return new Promise((resolve, reject) =>
        fooFn(options, (err, result) =>
            // If there's an error, reject; otherwise resolve
            err ? reject(err) : resolve(result)
        )
    );
}

Затем эту функцию можно использовать следующим образом:

promiseFooFn(options).then(result => {
    // success!
}).catch(err => {
    // error!
});

В более общем виде, вот как можно обещать любую функцию обратного вызова:

function promisify(func) {
    return function(...args) {
        return new Promise((resolve, reject) => {
            func(...args, (err, result) => err ? reject(err) : resolve(result));
        });
    }
}

Это можно использовать следующим образом:

const fs = require('fs');
const promisedStat = promisify(fs.stat.bind(fs));

promisedStat('/foo/bar')
    .then(stat => console.log('STATE', stat))
    .catch(err => console.log('ERROR', err));

Обработка ошибок

Ошибки, отбрасываемые из обещаний, обрабатываются вторым параметром ( reject ), переданным then или обработчиком, переданным для catch :

throwErrorAsync()
  .then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
  .catch(error => { /* handle error here */ });

Цепной

Если у вас есть цепочка обещаний, ошибка приведет к пропущению обработчиков resolve :

throwErrorAsync()
  .then(() => { /* never called */ })
  .catch(error => { /* handle error here */ });

То же самое относится к вашим then функциям. Если обработчик resolve генерирует исключение, тогда будет вызываться следующий обработчик reject :

doSomethingAsync()
  .then(result => { throwErrorSync(); })
  .then(() => { /* never called */ })
  .catch(error => { /* handle error from throwErrorSync() */ });

Обработчик ошибок возвращает новое обещание, позволяющее продолжить цепочку обещаний. Обещание, возвращенное обработчиком ошибок, разрешено со значением, возвращаемым обработчиком:

throwErrorAsync()
  .catch(error => { /* handle error here */; return result; })
  .then(result => { /* handle result here */ });

Вы можете позволить каскадной ошибке выполнить цепочку обещаний, повторно сбросив ошибку:

throwErrorAsync()
  .catch(error => {
      /* handle error from throwErrorAsync() */
      throw error;
  })
  .then(() => { /* will not be called if there's an error */ })
  .catch(error => { /* will get called with the same error */ });

Можно исключить исключение, которое не обрабатывается обещанием, обертывая оператор throw внутри обратного вызова setTimeout :

new Promise((resolve, reject) => {
  setTimeout(() => { throw new Error(); });
});

Это работает, потому что обещания не могут обрабатывать исключения, которые асинхронно обрабатываются.

Необработанные отказы

Ошибка будет игнорироваться, если в обещании нет блока catch или обработчика reject :

throwErrorAsync()
  .then(() => { /* will not be called */ });
// error silently ignored

Чтобы предотвратить это, всегда используйте блок catch :

throwErrorAsync()
  .then(() => { /* will not be called */ })
  .catch(error => { /* handle error*/ });
// or
throwErrorAsync()
  .then(() => { /* will not be called */ }, error => { /* handle error*/ });

Кроме того, подпишитесь на событие unhandledrejection чтобы поймать любые необработанные отклоненные обещания:

window.addEventListener('unhandledrejection', event => {});

Некоторые обещания могут обработать их отказ позже, чем время их создания. Событие, отклоняемое при rejectionhandled запускается каждый раз, когда выполняется такое обещание:

window.addEventListener('unhandledrejection', event => console.log('unhandled'));
window.addEventListener('rejectionhandled', event => console.log('handled'));
var p = Promise.reject('test');

setTimeout(() => p.catch(console.log), 1000);

// Will print 'unhandled', and after one second 'test' and 'handled'

Аргумент event содержит информацию об отказе. event.reason - объект ошибки и event.promise - объект обещания, который вызвал событие.

В Nodejs rejectionhandled и unhandledrejection события прерывания называются rejectionHandled и unhandledRejection on process , соответственно, и имеют другую подпись:

process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});

Аргумент reason - объект ошибки, а аргумент promise - это ссылка на объект обещания, который вызвал событие.

Использование этих unhandledrejection событий, связанных с unhandledrejection и rejectionhandled должно учитываться только для целей отладки. Как правило, все обещания должны обрабатывать их отклонения.

Примечание. В настоящее время только Chrome 49+ и Node.js поддерживают unhandledrejection события отмены и rejectionhandled .

Предостережения

Цепочка с fulfill и reject

Функция then(fulfill, reject) (с обоими параметрами не равна null ) имеет уникальное и сложное поведение и не должна использоваться, если вы точно не знаете, как это работает.

Функция работает как ожидалось, если для одного из входов задано значение null :

// the following calls are equivalent
promise.then(fulfill, null) 
promise.then(fulfill)

// the following calls are also equivalent
promise.then(null, reject) 
promise.catch(reject)

Однако он принимает уникальное поведение, когда даны оба входа:

// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.then(fulfill).catch(reject)

// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.catch(reject).then(fulfill)

Функция then(fulfill, reject) выглядит так, как будто это ярлык для then(fulfill).catch(reject) , но это не так, и это вызовет проблемы, если их использовать взаимозаменяемо. Одна из таких проблем заключается в том, что обработчик reject не обрабатывает ошибки из обработчика fulfill . Вот что будет:

Promise.resolve() // previous promise is fulfilled
    .then(() => { throw new Error(); }, // error in the fulfill handler
        error => { /* this is not called! */ });

Вышеприведенный код приведет к отклоненному обещанию, поскольку ошибка распространяется. Сравните его с приведенным ниже кодом, результатом которого является выполнение обещания:

Promise.resolve() // previous promise is fulfilled
    .then(() => { throw new Error(); }) // error in the fulfill handler
    .catch(error => { /* handle error */ });

Подобная проблема существует при использовании then(fulfill, reject) взаимозаменяемо с catch(reject).then(fulfill) , кроме как с распространением выполненных обещаний вместо отклоненных обещаний.

Синхронно выбрасывать из функции, которая должна вернуть обещание

Представьте себе такую ​​функцию:

function foo(arg) {
  if (arg === 'unexepectedValue') {
    throw new Error('UnexpectedValue')
  }

  return new Promise(resolve => 
    setTimeout(() => resolve(arg), 1000)
  )
}

Если такая функция используется в середине цепочки обещаний, то, по-видимому, нет проблем:

makeSomethingAsync().
  .then(() => foo('unexpectedValue'))
  .catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here

Однако, если одна и та же функция вызывается вне цепочки обещаний, тогда ошибка не будет обрабатываться ею и будет брошена в приложение:

foo('unexpectedValue') // <-- error will be thrown, so the application will crash
  .then(makeSomethingAsync) // <-- will not run
  .catch(err => console.log(err)) // <-- will not catch

Возможны два способа обхода:

Вернуть отклоненное обещание с ошибкой

Вместо того, чтобы бросать, сделайте следующее:

function foo(arg) {
  if (arg === 'unexepectedValue') {
    return Promise.reject(new Error('UnexpectedValue'))
  }

  return new Promise(resolve => 
    setTimeout(() => resolve(arg), 1000)
  )
}

Оберните свою функцию в цепочку обещаний

Ваша throw будет правильно поймана, когда она уже находится в цепочке обещаний:

function foo(arg) {
  return Promise.resolve()
    .then(() => {
      if (arg === 'unexepectedValue') {
        throw new Error('UnexpectedValue')
      }

      return new Promise(resolve => 
        setTimeout(() => resolve(arg), 1000)
      )
    })
}

Согласование синхронных и асинхронных операций

В некоторых случаях вам может понадобиться обернуть синхронную операцию внутри обещания, чтобы предотвратить повторение в ветвях кода. Возьмем следующий пример:

if (result) { // if we already have a result
  processResult(result); // process it
} else {
  fetchResult().then(processResult);
}

Синхронные и асинхронные ветви вышеуказанного кода могут быть согласованы путем избыточной упаковки синхронной операции внутри обещания:

var fetch = result
  ? Promise.resolve(result)
  : fetchResult();

fetch.then(processResult);

При кешировании результата асинхронного вызова предпочтительнее кэшировать обещание, а не сам результат. Это гарантирует, что для разрешения нескольких параллельных запросов требуется только одна асинхронная операция.

Следует соблюдать осторожность при аннулировании кешированных значений при возникновении условий ошибки.

// A resource that is not expected to change frequently
var planets = 'http://swapi.co/api/planets/';
// The cached promise, or null
var cachedPromise;

function fetchResult() {
    if (!cachedPromise) {
        cachedPromise = fetch(planets)
            .catch(function (e) {
                // Invalidate the current result to retry on the next fetch
                cachedPromise = null;
                // re-raise the error to propagate it to callers
                throw e;
            });
    }
    return cachedPromise;
}

Уменьшите массив до целых обещаний

Этот шаблон проектирования полезен для генерации последовательности асинхронных действий из списка элементов.

Существует два варианта:

  • «затем» сокращение, которое строит цепочку, которая продолжается до тех пор, пока цепь испытывает успех.
  • сокращение «уловки», которое строит цепочку, которая продолжается до тех пор, пока цепь испытывает ошибку.

«Затем» сокращение

Этот вариант шаблона создает цепочку .then() и может использоваться для цепочки анимации или создания последовательности зависимых HTTP-запросов.

[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.then(() => {
        console.log(n);
        return new Promise(res => setTimeout(res, 1000));
    });
}, Promise.resolve()).then(
    () => console.log('done'),
    (e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals

Объяснение:

  1. Мы вызываем .reduce() в исходном массиве и предоставляем Promise.resolve() в качестве начального значения.
  2. Каждый уменьшенный элемент добавит a .then() к исходному значению.
  3. reduce() «s продукт будет Promise.resolve (). Затем (...). Затем (...).
  4. Мы вручную добавляем .then(successHandler, errorHandler) после сокращения, чтобы выполнить successHandler только все предыдущие шаги разрешены. Если какой-либо шаг должен завершиться неудачей, тогда будет выполняться errorHandler .

Примечание. Уменьшение «затем» является последовательным аналогом Promise.all() .

Сокращение «уловов»

Этот вариант шаблона создает .catch() и может использоваться для последовательного зондирования набора веб-серверов для некоторого зеркального ресурса до тех пор, пока не будет найден рабочий сервер.

var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.catch(() => {
        console.log(n);
        if(n === working_resource) { // 5 is working
            return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
        } else { // all other values are not working
            return new Promise((resolve, reject) => setTimeout(reject, 1000));
        }
    });
}, Promise.reject()).then(
    (n) => console.log('success at: ' + n),
    () => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals

Объяснение:

  1. Мы вызываем .reduce() в исходном массиве и предоставляем Promise.reject() в качестве начального значения.
  2. Каждый уменьшенный элемент добавит .catch() к исходному значению.
  3. reduce() «s продукт будет Promise.reject().catch(...).catch(...) .
  4. Мы вручную добавляем .then(successHandler, errorHandler) после сокращения, чтобы выполнить successHandler только любой из предыдущих шагов разрешился. Если все шаги errorHandler с ошибкой, тогда будет выполняться errorHandler .

Примечание. Сокращение «catch» является последовательным аналогом Promise.any() (как реализовано в bluebird.js , но не в настоящее время в родном ECMAScript).

forEach с обещаниями

Можно эффективно применить функцию ( cb ), которая возвращает обещание каждому элементу массива, причем каждый элемент ожидает обработки до тех пор, пока не будет обработан предыдущий элемент.

function promiseForEach(arr, cb) {
  var i = 0;

  var nextPromise = function () {
    if (i >= arr.length) {
      // Processing finished.
      return;
    }

    // Process next function. Wrap in `Promise.resolve` in case
    // the function does not return a promise
    var newPromise = Promise.resolve(cb(arr[i], i));
    i++;
    // Chain to finish processing.
    return newPromise.then(nextPromise);
  };

  // Kick off the chain.
  return Promise.resolve().then(nextPromise);
};

Это может быть полезно, если вам нужно эффективно обрабатывать тысячи предметов, по одному за раз. Использование регулярного for цикла , чтобы создать обещания будут создавать их все сразу и занимают значительное количество оперативной памяти.

Выполнение очистки с помощью finally ()

В настоящее время есть предложение (еще не включенное в стандарт ECMAScript), чтобы добавить finally ответ на обещания, которые будут выполнены независимо от того, выполняется ли обещание или отклонено. Семантически это похоже на предложение finally блока try .

Обычно вы используете эту функцию для очистки:

var loadingData = true;

fetch('/data')
    .then(result => processData(result.data))
    .catch(error => console.error(error))
    .finally(() => {
        loadingData = false;
    });

Важно отметить, что finally обратный вызов не влияет на состояние обещания. Неважно, какое значение оно возвращает, обещание остается в отложенном / отвергнутом состоянии, которое оно имело раньше. Таким образом, в приведенном выше примере обещание будет разрешено с возвращаемым значением processData(result.data) хотя finally обратный вызов возвращается undefined .

Когда процесс стандартизации все еще продолжается, реализация ваших обещаний, скорее всего, не будет поддерживать finally обратные вызовы из коробки. Для синхронных обратных вызовов вы можете добавить эту функцию с помощью polyfill:

if (!Promise.prototype.finally) {
    Promise.prototype.finally = function(callback) {
        return this.then(result => {
            callback();
            return result;
        }, error => {
            callback();
            throw error;
        });
    };
}

Запрос асинхронного API

Это пример простого вызова API GET заверенного обещанием воспользоваться его асинхронными функциями.

var get = function(path) {
  return new Promise(function(resolve, reject) {
    let request = new XMLHttpRequest();
    request.open('GET', path);
    request.onload = resolve;
    request.onerror = reject;
    request.send();
  });
};

Более надежная обработка ошибок может быть выполнена с использованием следующих функций onload и onerror .

request.onload = function() {
  if (this.status >= 200 && this.status < 300) {
    if(request.response) {
      // Assuming a successful call returns JSON
      resolve(JSON.parse(request.response));
    } else {
      resolve();
  } else {
    reject({
      'status': this.status,
      'message': request.statusText
    });
  }
};

request.onerror = function() {
  reject({
    'status': this.status,
    'message': request.statusText
  });
};

Использование ES2017 async / wait

Тот же пример выше, Загрузка изображения , может быть записан с использованием асинхронных функций . Это также позволяет использовать общий метод try/catch для обработки исключений.

Примечание: по состоянию на апрель 2017 года текущие выпуски всех браузеров, но Internet Explorer поддерживает функции async .

function loadImage(url) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.addEventListener('load', () => resolve(img));
        img.addEventListener('error', () => {
            reject(new Error(`Failed to load ${url}`));
        });
        img.src = url;
    });
}

(async () => {

    // load /image.png and append to #image-holder, otherwise throw error
    try {
        let img = await loadImage('http://example.com/image.png');
        document.getElementById('image-holder').appendChild(img);
    }
    catch (error) {
        console.error(error);
    }

})();


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow