Поиск…
Синтаксис
- новая функция 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
Объяснение:
- Мы вызываем
.reduce()
в исходном массиве и предоставляемPromise.resolve()
в качестве начального значения. - Каждый уменьшенный элемент добавит a
.then()
к исходному значению. -
reduce()
«s продукт будет Promise.resolve (). Затем (...). Затем (...). - Мы вручную добавляем
.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
Объяснение:
- Мы вызываем
.reduce()
в исходном массиве и предоставляемPromise.reject()
в качестве начального значения. - Каждый уменьшенный элемент добавит
.catch()
к исходному значению. -
reduce()
«s продукт будетPromise.reject().catch(...).catch(...)
. - Мы вручную добавляем
.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);
}
})();