Sök…
Syntax
- ny Löfte (/ * exekutivfunktion: * / funktion (lösa, avvisa) {})
- lover.then (onFulfilled [, onRejected])
- promise.catch (onRejected)
- Promise.resolve (upplösning)
- Promise.reject (orsak)
- Promise.all (iterable)
- Promise.race (iterable)
Anmärkningar
Löften är en del av ECMAScript 2015-specifikationen och webbläsarsupport är begränsat, med 88% av webbläsarna världen över som stöder det från juli 2017. Följande tabell ger en översikt över de tidigaste webbläsarversionerna som ger stöd för löften.
Krom | Kant | Firefox | Internet Explorer | Opera | Opera Mini | Safari | iOS Safari |
---|---|---|---|---|---|---|---|
32 | 12 | 27 | x | 19 | x | 7,1 | 8 |
I miljöer som inte stöder dem kan Promise
polyfyllas. Tredjepartsbibliotek kan också tillhandahålla utökade funktioner, till exempel automatiserad "promisification" av återuppringningsfunktioner eller ytterligare metoder som progress
- även känd som notify
.
Promises / A + standardwebbplatsen innehåller en lista med 1.0 och 1.1-kompatibla implementationer . Löfte återuppringningar baserade på A + -standarden utförs alltid asynkront som mikrotaskar i händelsslingan .
Löfte kedja
Den then
metoden för ett löfte ger ett nytt löfte.
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 */ });
Returnera en Promise
från en then
återuppringning kommer att lägga till löftet kedjan.
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 */ });
En catch
tillåter ett avvisat löfte att återhämta sig, liknande hur catch
i ett try
/ catch
fungerar. Alla kedjade then
efter en catch
kommer att utföra sin upplösningshanterare med hjälp av det värde som löses från catch
.
const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console)); // outputs "oh yes"
Om det inte finns några catch
eller reject
hanterare i mitten av kedjan, kommer en catch
i slutet att fånga avslag i kedjan:
p.catch(() => Promise.reject('oh yes'))
.then(console.log.bind(console)) // won't be called
.catch(console.error.bind(console)); // outputs "oh yes"
Vid vissa tillfällen kanske du vill "grenas" utförandet av funktionerna. Du kan göra det genom att returnera olika löften från en funktion beroende på villkor. Senare i koden kan du slå samman alla dessa grenar till en för att kalla andra funktioner på dem och / eller för att hantera alla fel på ett ställe.
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);
});
Således ser exekveringsordning för funktionerna ut:
promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
| ^
V |
-> handlerFn3 -> handlerFn4 -^
Den enskilda catch
får felet på vilken gren den än kan förekomma.
Introduktion
Ett Promise
representerar en operation som har producerat eller så småningom ger ett värde. Löften ger ett robust sätt att ta bort det (eventuellt pågående) resultatet av asynkront arbete, vilket mildrar problemet med djupt kapslade återuppringningar (känd som " callback helvete ").
Tillstånd och kontrollflöde
Ett löfte kan vara i en av tre stater:
- avvaktande - Den underliggande operationen har ännu inte slutförts, och löfte är i väntan på uppfyllande.
- uppfylld - Åtgärden är klar och löften uppfylls med ett värde . Detta är analogt med att returnera ett värde från en synkron funktion.
- avvisad - Ett fel har inträffat under operationen, och löfte avvisas med anledning . Detta är analogt med att kasta ett fel i en synkronfunktion.
Ett löfte sägs vara avgjort (eller löst ) när det antingen uppfylls eller förkastas. När ett löfte är avgjort blir det oföränderligt och dess tillstånd kan inte förändras. then
och catch
för ett löfte kan användas för att bifoga återuppringningar som körs när det är avgjort. Dessa återuppringningar åberopas med uppfyllande respektive avvisningsskäl.
Exempel
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
och catch
kan användas för att bifoga uppfyllande och avvisande återuppringningar:
promise.then(value => {
// Work has completed successfully,
// promise has been fulfilled with "value"
}).catch(reason => {
// Something went wrong,
// promise has been rejected with "reason"
});
Obs: Att ringa promise.then(...)
och promise.catch(...)
på samma löfte kan leda till ett Uncaught exception in Promise
om ett fel inträffar, antingen vid genomförandet av löfte eller i en av återuppringningarna, så det föredragna sättet skulle vara att fästa nästa lyssnare på det löfte som returnerades av den föregående then
/ catch
.
Alternativt kan båda återuppringningarna bifogas i ett enda samtal till then
:
promise.then(onFulfilled, onRejected);
Om du kopplar återuppringningar till ett löfte som redan har fastställts kommer de omedelbart att placeras i mikrotaskkön , och de kommer att åberopas "så snart som möjligt" (dvs. omedelbart efter det nuvarande exekverande skriptet). Det är inte nödvändigt att kontrollera löftets tillstånd innan du kopplar återuppringningar, till skillnad från många andra händelsemitterande implementationer.
Fördröjningsfunktionssamtal
setTimeout()
kallar en funktion eller utvärderar ett uttryck efter ett specificerat antal millisekunder. Det är också ett trivialt sätt att uppnå en asynkron operation.
I det här exemplet löser man wait
funktionen löften efter den tid som anges som första argument:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
wait(5000).then(() => {
console.log('5 seconds have passed...');
});
Väntar på flera samtidiga löften
Den statiska metoden Promise.all()
accepterar en iterbar (t.ex. en Array
) av löften och returnerar ett nytt löfte, som löses när alla löften i det iterable har lösts, eller avvisar om åtminstone ett av löftena i det iterable har avvisat.
// 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.
Värden som inte är löfte i det iterable "lovas" .
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
{ hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds
Destruktureringsuppdrag kan hjälpa till att hämta resultat från flera löften.
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
console.log(result1);
console.log(result2);
console.log(result3);
});
Väntar på det första av flera samtidiga löften
Den statiska metoden Promise.race()
accepterar en iterable of Promises och returnerar ett nytt lovande som löser eller avvisar så snart det första av löften i iterable har lösts eller avvisats.
// 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" -värden
Den statiska metoden Promise.resolve
kan användas för att förpacka värden till löften.
let resolved = Promise.resolve(2);
resolved.then(value => {
// immediately invoked
// value === 2
});
Om value
redan är ett löfte omarbetar Promise.resolve
helt enkelt det.
let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
// 1 second has passed
// value === 2
});
I själva verket kan value
vara vilket som helst "dåligt" (objekt som definierar en then
metod som fungerar tillräckligt som ett spec-kompatibelt löfte). Detta tillåter Promise.resolve
att konvertera otillförlitliga tredje part-objekt till pålitliga första-partslöften.
let resolved = Promise.resolve({
then(onResolved) {
onResolved(2);
}
});
resolved.then(value => {
// immediately invoked
// value === 2
});
Den statiska metoden Promise.reject
returnerar ett löfte som omedelbart avvisar med det angivna reason
.
let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
// immediately invoked
// reason === "Oops!"
});
"Promisifying" -funktioner med återuppringningar
Med tanke på en funktion som accepterar en återuppringning i Node-stil,
fooFn(options, function callback(err, result) { ... });
Du kan lova det (konvertera det till en löfte-baserad funktion) så här:
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)
)
);
}
Denna funktion kan sedan användas på följande sätt:
promiseFooFn(options).then(result => {
// success!
}).catch(err => {
// error!
});
På ett mer generiskt sätt så här kan du lova en given återuppringningsstil:
function promisify(func) {
return function(...args) {
return new Promise((resolve, reject) => {
func(...args, (err, result) => err ? reject(err) : resolve(result));
});
}
}
Detta kan användas så här:
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));
Felhantering
Fel som kastas från löften hanteras av den andra parametern ( reject
) som skickas till then
eller av hanteraren som skickas för att catch
:
throwErrorAsync()
.then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
.catch(error => { /* handle error here */ });
kedja
Om du har en löftskedja kommer ett fel att resolve
hanterare att hoppa över:
throwErrorAsync()
.then(() => { /* never called */ })
.catch(error => { /* handle error here */ });
Detsamma gäller för dina then
funktioner. Om en resolve
handler kastar ett undantag sedan nästa reject
hanterare kommer att åberopas:
doSomethingAsync()
.then(result => { throwErrorSync(); })
.then(() => { /* never called */ })
.catch(error => { /* handle error from throwErrorSync() */ });
En felhanterare returnerar ett nytt löfte så att du kan fortsätta med en löftskedja. Löfte som returneras av felhanteraren löses med värdet som returneras av hanteraren:
throwErrorAsync()
.catch(error => { /* handle error here */; return result; })
.then(result => { /* handle result here */ });
Du kan låta ett fel kaskadera ner en löftskedja genom att kasta felet igen:
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 */ });
Det är möjligt att kasta ett undantag som inte hanteras av löftet genom att linda throw
uttalande i en setTimeout
återuppringning:
new Promise((resolve, reject) => {
setTimeout(() => { throw new Error(); });
});
Detta fungerar eftersom löften inte kan hantera undantag som kastas asynkront.
Obehandlade avslag
Ett fel ignoreras tyst om ett löfte inte har ett catch
eller reject
hanterare:
throwErrorAsync()
.then(() => { /* will not be called */ });
// error silently ignored
Använd alltid ett catch
att förhindra detta:
throwErrorAsync()
.then(() => { /* will not be called */ })
.catch(error => { /* handle error*/ });
// or
throwErrorAsync()
.then(() => { /* will not be called */ }, error => { /* handle error*/ });
Alternativt, prenumerera på unhandledrejection
händelsen för att fånga eventuella Ohanterad avvisade löften:
window.addEventListener('unhandledrejection', event => {});
Vissa löften kan hantera deras avslag senare än deras skapelsestid. Händelsen som rejectionhandled
hanteras varje gång ett sådant löfte hanteras:
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
innehåller information om avslaget. event.reason
är event.reason
och event.promise
är det event.promise
som orsakade händelsen.
I Nodejs kallas rejectionhandled
och unhandledrejection
händelserhändelser rejectionHandled
och unhandledRejection
vid process
respektive och har en annan signatur:
process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});
reason
är felobjektet och promise
är en hänvisning till löfteobjektet som fick händelsen att skjutas.
Användning av dessa unhandledrejection
och rejectionhandled
händelser bör övervägas för endast felsökning. Vanligtvis bör alla löften hantera deras avslag.
OBS: För närvarande bara Chrome 49+ och Node.js support unhandledrejection
och rejectionhandled
händelser.
förbehåll
Kedja med fulfill
och reject
Funktionen then(fulfill, reject)
(med båda parametrarna inte null
) har unikt och komplext beteende och bör inte användas om du inte vet exakt hur det fungerar.
Funktionen fungerar som förväntat om den ges null
för en av ingångarna:
// 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)
Det antar emellertid unikt beteende när båda ingångar ges:
// 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)
Funktionen then(fulfill, reject)
ser ut som om det är en genväg för then(fulfill).catch(reject)
, men det är det inte och kommer att orsaka problem om de används omväxlande. Ett sådant problem är att den reject
hanteraren inte hanterar fel från fulfill
. Här är vad som kommer att hända:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }, // error in the fulfill handler
error => { /* this is not called! */ });
Ovanstående kod kommer att resultera i ett avvisat löfte eftersom felet sprids. Jämför den med följande kod, vilket resulterar i ett uppfyllt löfte:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }) // error in the fulfill handler
.catch(error => { /* handle error */ });
Ett liknande problem existerar när man då använder then(fulfill, reject)
utbytbart med catch(reject).then(fulfill)
, förutom med att sprida uppfyllda löften istället för avvisade löften.
Synkront kasta från funktion som borde ge ett löfte
Föreställ dig en sådan funktion:
function foo(arg) {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
Om en sådan funktion används i mitten av en löftskedja är det uppenbarligen inga problem:
makeSomethingAsync().
.then(() => foo('unexpectedValue'))
.catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here
Men om samma funktion kallas utanför en löftskedja, kommer felet inte att hanteras av det och kommer att kastas till applikationen:
foo('unexpectedValue') // <-- error will be thrown, so the application will crash
.then(makeSomethingAsync) // <-- will not run
.catch(err => console.log(err)) // <-- will not catch
Det finns två möjliga lösningar:
Returnera ett avvisat löfte med felet
Gör så här istället för att kasta:
function foo(arg) {
if (arg === 'unexepectedValue') {
return Promise.reject(new Error('UnexpectedValue'))
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
Förpacka din funktion i en löfte kedja
Ditt throw
kommer att fångas ordentligt när det redan finns i en löftskedja:
function foo(arg) {
return Promise.resolve()
.then(() => {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
})
}
Avstämma synkrona och asynkrona operationer
I vissa fall kanske du vill linda in en synkron operation i ett löfte om att förhindra upprepning i kodgrenar. Ta detta exempel:
if (result) { // if we already have a result
processResult(result); // process it
} else {
fetchResult().then(processResult);
}
De synkrona och asynkrona grenarna i koden ovan kan förenas genom att den synkrona operationen redundant lindas in i ett löfte:
var fetch = result
? Promise.resolve(result)
: fetchResult();
fetch.then(processResult);
När cachar resultatet av ett asynkront samtal är det att föredra att cache löftet snarare än själva resultatet. Detta säkerställer att endast en asynkron operation krävs för att lösa flera parallella förfrågningar.
Försiktighet bör iakttas att ogiltiga cachedvärden ogiltigförklaras när felförhållanden uppstår.
// 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;
}
Minska en grupp till länkade löften
Detta designmönster är användbart för att generera en sekvens av asynkrona åtgärder från en lista över element.
Det finns två varianter:
- den "då" reduktionen, som bygger en kedja som fortsätter så länge kedjan upplever framgång.
- "fångst" -minskningen, som bygger en kedja som fortsätter så länge kedjan upplever fel.
Den "då" minskningen
Denna variant av mönstret bygger en .then()
-kedja och kan användas för att kedja animationer eller göra en sekvens av beroende HTTP-förfrågningar.
[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
Förklaring:
- Vi kallar
.reduce()
på en källarray och tillhandahållerPromise.resolve()
som ett initialvärde. - Varje reducerat element lägger till ett
.then()
till det initiala värdet. -
reduce()
: s produkt kommer att vara Promise.resolve (). sedan (...). sedan (...). - Vi lägger manuellt till en
.then(successHandler, errorHandler)
efter reduceringen för att utförasuccessHandler
när alla tidigare steg har lösts. Om något steg skulle misslyckas, skulleerrorHandler
köra.
Obs: "Då" -reduktionen är en sekventiell motsvarighet till Promise.all()
.
"Fångst" -minskningen
Denna variant av mönstret bygger en .catch()
-kedja och kan användas för att sekventiellt undersöka en uppsättning webbserver för någon speglad resurs tills en fungerande server hittas.
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
Förklaring:
- Vi kallar
.reduce()
på en källarray och tillhandahållerPromise.reject()
som ett initialvärde. - Varje element som reduceras lägger till en
.catch()
till det initiala värdet. -
reduce()
: s produkt kommer att varaPromise.reject().catch(...).catch(...)
. - Vi lägger manuellt till
.then(successHandler, errorHandler)
efter reduceringen, för att utförasuccessHandler
när något av de tidigare stegen har lösts. Om alla steg skulle misslyckas, skulleerrorHandler
utföra.
Obs: "Fångst" -minskningen är en sekventiell motsvarighet till Promise.any()
(implementerad i bluebird.js
, men för närvarande inte i det egna ECMAScript).
för alla med löften
Det är möjligt att effektivt tillämpa en funktion ( cb
) som returnerar ett löfte till varje element i en matris, där varje element väntar på att bearbetas tills det föregående elementet bearbetas.
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);
};
Detta kan vara till hjälp om du behöver bearbeta tusentals artiklar på en gång. Att använda en vanlig for
loop för att skapa löften skapar dem alla på en gång och tar upp en betydande mängd RAM.
Utför rensning med äntligen ()
Det finns för närvarande ett förslag (ännu inte en del av ECMAScript-standarden) att lägga till ett finally
återuppringning till löften som kommer att genomföras oavsett om löften uppfylls eller förkastas. Semantiskt, är detta liknar det finally
klausul i try
blocket .
Du brukar använda den här funktionen för sanering:
var loadingData = true;
fetch('/data')
.then(result => processData(result.data))
.catch(error => console.error(error))
.finally(() => {
loadingData = false;
});
Det är viktigt att notera att den finally
återuppringningen inte påverkar löftets tillstånd. Det spelar ingen roll vilket värde det returnerar, löfteet förblir i det uppfyllda / avvisade tillståndet som det hade tidigare. Så i exemplet ovan kommer löftet att lösas med returvärdet för processData(result.data)
även om den finally
återuppringningen returneras undefined
.
När standardiseringsprocessen fortfarande pågår stöder ditt implementering av löften sannolikt inte finally
återuppringningar ur ramen. För synkrona återuppringningar kan du dock lägga till den här funktionen med en polyfyll:
if (!Promise.prototype.finally) {
Promise.prototype.finally = function(callback) {
return this.then(result => {
callback();
return result;
}, error => {
callback();
throw error;
});
};
}
Asynkron API-begäran
Detta är ett exempel på ett enkelt GET
API-samtal inslaget i ett löfte om att dra fördel av dess asynkrona funktionalitet.
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();
});
};
Mer robust felhantering kan göras med följande onload
och onerror
funktioner.
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
});
};
Använda ES2017 async / invänta
Samma exempel ovan, Image loading , kan skrivas med hjälp av async-funktioner . Detta gör det också möjligt att använda den vanliga try/catch
metoden för undantagshantering.
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);
}
})();