Zoeken…
Syntaxis
- nieuwe belofte (/ * uitvoerderfunctie: * / functie (oplossen, weigeren) {})
- belofte.then (onFulfilled [, onRejected])
- promise.catch (onRejected)
- Promise.resolve (resolutie)
- Promise.reject (reden)
- Promise.all (iterable)
- Promise.race (iterable)
Opmerkingen
Beloften maken deel uit van de ECMAScript 2015-specificatie en browserondersteuning is beperkt, 88% van de browsers ondersteunt dit vanaf juli 2017. De volgende tabel geeft een overzicht van de vroegste browserversies die ondersteuning bieden voor beloften.
Chrome | Rand | Firefox | Internet Explorer | Opera | Opera Mini | Safari | iOS Safari |
---|---|---|---|---|---|---|---|
32 | 12 | 27 | X | 19 | X | 7.1 | 8 |
In omgevingen die hen niet ondersteunen, kan Promise
polyfill zijn. Bibliotheken van derden kunnen ook uitgebreide functionaliteiten bieden, zoals geautomatiseerde "belofte" van callback-functies of aanvullende methoden zoals progress
- ook bekend als notify
.
De standaardwebsite van Promises / A + biedt een lijst met implementaties die voldoen aan 1.0 en 1.1 . Promise callbacks op basis van de A + -standaard worden altijd asynchroon uitgevoerd als microtaken in de gebeurtenislus .
Promise chaining
De then
methode van een belofte levert een nieuwe belofte op.
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 */ });
Het terugsturen van een Promise
van een then
callback zal toevoegen aan de belofte keten.
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 */ });
Met een catch
kan een afgewezen belofte worden hersteld, vergelijkbaar met hoe de catch
in een try
/ catch
verklaring werkt. Elke ketting then
na een catch
wordt gekoppeld, voert zijn oplossingshandler uit met de waarde die is opgelost uit de catch
.
const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console)); // outputs "oh yes"
Als er geen catch
of reject
handlers in het midden van de keten, een catch
zal aan het einde verwerping in de keten vast te leggen:
p.catch(() => Promise.reject('oh yes'))
.then(console.log.bind(console)) // won't be called
.catch(console.error.bind(console)); // outputs "oh yes"
In bepaalde gevallen wilt u misschien de uitvoering van de functies "vertakken". U kunt dit doen door verschillende beloften van een functie te retourneren, afhankelijk van de voorwaarde. Later in de code kunt u al deze takken samenvoegen tot één om andere functies aan te roepen en / of om alle fouten op één plaats af te handelen.
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);
});
De uitvoeringsvolgorde van de functies ziet er dus als volgt uit:
promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
| ^
V |
-> handlerFn3 -> handlerFn4 -^
De enkele catch
krijgt de fout op welke tak het ook kan optreden.
Invoering
Een Promise
object vertegenwoordigt een bewerking die een waarde heeft geproduceerd of uiteindelijk zal produceren . Beloftes bieden een robuuste manier om het (mogelijk in behandeling) resultaat van asynchroon werk te omzeilen, waardoor het probleem van diep geneste callbacks (bekend als " callback hell ") wordt beperkt .
Staten en controle stroom
Een belofte kan in een van de drie staten zijn:
- in behandeling - de onderliggende bewerking is nog niet voltooid en de belofte is in afwachting van de vervulling.
- vervuld - De bewerking is voltooid en de belofte is vervuld met een waarde . Dit is analoog aan het retourneren van een waarde uit een synchrone functie.
- afgewezen - Er is een fout opgetreden tijdens de bewerking en de belofte is afgewezen met een reden . Dit is analoog aan het gooien van een fout in een synchrone functie.
Er wordt gezegd dat een belofte wordt afgehandeld (of opgelost ) wanneer deze wordt vervuld of afgewezen. Als een belofte eenmaal is geregeld, wordt deze onveranderlijk en kan de staat ervan niet meer veranderen. De then
en de catch
methoden een belofte die kan worden gebruikt om callbacks dat uit te voeren wanneer het wordt afgewikkeld hechten. Deze callbacks worden respectievelijk aangeroepen met de uitvoeringswaarde en de afwijzingsreden.
Voorbeeld
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;
}
});
De methoden then
en catch
kunnen worden gebruikt om callbacks voor de uitvoering en afwijzing toe te voegen:
promise.then(value => {
// Work has completed successfully,
// promise has been fulfilled with "value"
}).catch(reason => {
// Something went wrong,
// promise has been rejected with "reason"
});
Opmerking: Calling promise.then(...)
en promise.catch(...)
op dezelfde belofte kan resulteren in een Niet- Uncaught exception in Promise
als er een fout optreedt, hetzij tijdens het uitvoeren van de belofte of binnen een van de callbacks, dus de beste manier zou zijn om de volgende luisteraar te binden aan de belofte van de vorige then
/ catch
.
Als alternatief kunnen beide terugbelgesprekken in één gesprek worden toegevoegd en then
:
promise.then(onFulfilled, onRejected);
Door callbacks toe te voegen aan een belofte die al is afgehandeld, worden ze onmiddellijk in de wachtrij voor microtask geplaatst en worden ze "zo snel mogelijk" (dwz direct na het script dat momenteel wordt uitgevoerd) opgeroepen. Het is niet nodig om de status van de belofte te controleren voordat callbacks worden toegevoegd, in tegenstelling tot veel andere event-emitting implementaties.
Oproep functie uitstellen
De methode setTimeout()
roept een functie aan of evalueert een uitdrukking na een opgegeven aantal milliseconden. Het is ook een triviale manier om een asynchrone bewerking te bereiken.
In dit voorbeeld is het aanroepen van de wait
functie lost de belofte na de tijd opgegeven als eerste argument:
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
wait(5000).then(() => {
console.log('5 seconds have passed...');
});
Wachten op meerdere gelijktijdige beloften
De statische methode Promise.all()
accepteert een iterabele (bijvoorbeeld een Array
) van beloften en retourneert een nieuwe belofte, die wordt opgelost wanneer alle beloften in de iterabele zijn opgelost, of weigert als ten minste een van de beloften in de iterabele is afgewezen.
// 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.
Niet-beloftewaarden in de iterabele zijn "beloofd" .
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
{ hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds
Destructureringsopdracht kan helpen om resultaten van meerdere beloften op te halen.
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
console.log(result1);
console.log(result2);
console.log(result3);
});
Wachten op de eerste van meerdere gelijktijdige beloften
De statische methode Promise.race()
accepteert een iterabel van Promises en retourneert een nieuwe Promise die wordt opgelost of afgewezen zodra de eerste van de beloften in de iterable is opgelost of afgewezen.
// 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
"Veelbelovende" waarden
De statische methode Promise.resolve
kan worden gebruikt om waarden om te zetten in beloften.
let resolved = Promise.resolve(2);
resolved.then(value => {
// immediately invoked
// value === 2
});
Als value
al een belofte is, Promise.resolve
Promise.resolve deze eenvoudig.
let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
// 1 second has passed
// value === 2
});
value
kan in feite elk "te gebruiken" zijn (object dat een then
methode definieert die voldoende werkt als een spec-compliant belofte). Hiermee kan Promise.resolve
niet-vertrouwde objecten van derden converteren naar vertrouwde beloften van derden.
let resolved = Promise.resolve({
then(onResolved) {
onResolved(2);
}
});
resolved.then(value => {
// immediately invoked
// value === 2
});
De statische methode Promise.reject
retourneert een belofte die onmiddellijk met de opgegeven reason
afgewezen.
let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
// immediately invoked
// reason === "Oops!"
});
"Veelbelovende" functies met callbacks
Gegeven een functie die een Node-stijl callback accepteert,
fooFn(options, function callback(err, result) { ... });
u kunt het beloven (omzetten naar een op beloften gebaseerde functie) als volgt:
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)
)
);
}
Deze functie kan vervolgens als volgt worden gebruikt:
promiseFooFn(options).then(result => {
// success!
}).catch(err => {
// error!
});
Op een meer generieke manier kunt u als volgt een functie voor callback-stijl beloven:
function promisify(func) {
return function(...args) {
return new Promise((resolve, reject) => {
func(...args, (err, result) => err ? reject(err) : resolve(result));
});
}
}
Dit kan als volgt worden gebruikt:
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));
Foutafhandeling
Fouten die uit beloftes zijn gegooid, worden afgehandeld door de tweede parameter ( reject
) die then
doorgegeven of door de doorgegeven handler om te catch
:
throwErrorAsync()
.then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
.catch(error => { /* handle error here */ });
chaining
Als u een belofteketen hebt, zal een fout ertoe leiden dat handlers voor resolve
worden overgeslagen:
throwErrorAsync()
.then(() => { /* never called */ })
.catch(error => { /* handle error here */ });
Hetzelfde geldt voor uw then
functies. Als een resolve
handler gooit een uitzondering dan de volgende reject
handler zal worden aangeroepen:
doSomethingAsync()
.then(result => { throwErrorSync(); })
.then(() => { /* never called */ })
.catch(error => { /* handle error from throwErrorSync() */ });
Een foutafhandelaar retourneert een nieuwe belofte, zodat u een belofteketen kunt voortzetten. De belofte die door de error-handler wordt geretourneerd, wordt opgelost met de waarde die door de handler wordt geretourneerd:
throwErrorAsync()
.catch(error => { /* handle error here */; return result; })
.then(result => { /* handle result here */ });
Je kunt een fout in een belofte laten vallen door de fout opnieuw te gooien:
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 */ });
Het is mogelijk om een uitzondering te gooien die niet door de belofte wordt afgehandeld door de throw
instructie in een setTimeout
callback te plaatsen:
new Promise((resolve, reject) => {
setTimeout(() => { throw new Error(); });
});
Dit werkt omdat beloften niet kunnen omgaan met asynchroon gegooide uitzonderingen.
Onbehandelde afwijzingen
Een fout zal in stilte worden genegeerd als een belofte van een niet over catch
blok of reject
handler:
throwErrorAsync()
.then(() => { /* will not be called */ });
// error silently ignored
Gebruik altijd een catch
om dit te voorkomen:
throwErrorAsync()
.then(() => { /* will not be called */ })
.catch(error => { /* handle error*/ });
// or
throwErrorAsync()
.then(() => { /* will not be called */ }, error => { /* handle error*/ });
U kunt ook abonneren op de unhandledrejection
evenement om onverwerkte verworpen beloften te vangen:
window.addEventListener('unhandledrejection', event => {});
Sommige beloften kunnen hun afwijzing later aan dan hun tijd van creatie. De rejectionhandled
wordt ontslagen wanneer een dergelijke belofte wordt afgehandeld:
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'
Het event
bevat informatie over de afwijzing. event.reason
is het event.promise
en event.promise
is het event.promise
dat de gebeurtenis heeft veroorzaakt.
In Nodejs worden de rejectionhandled
en unhandledrejection
rejectionHandled
respectievelijk rejectionHandled
en unhandledRejection
rejectionHandled
in process
genoemd en hebben ze een andere handtekening:
process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});
De reason
argument is de fout object en de promise
argument is een verwijzing naar de belofte object dat de gebeurtenis heeft veroorzaakt brand.
Gebruik van deze unhandledrejection
rejectionhandled
en rejectionhandled
mag alleen worden overwogen voor foutopsporing. Doorgaans moeten alle beloften hun afwijzingen verwerken.
Opmerking: Momenteel zijn alleen Chrome 49+ en Node.js ondersteuning unhandledrejection
en rejectionhandled
evenementen.
Voorbehoud
Kettingen met fulfill
en reject
De then(fulfill, reject)
(met beide parameters niet null
) heeft een uniek en complex gedrag en mag alleen worden gebruikt als u precies weet hoe het werkt.
De functie werkt zoals verwacht als deze null
voor een van de ingangen:
// 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)
Het neemt echter uniek gedrag aan wanneer beide ingangen worden gegeven:
// 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)
De functie then(fulfill, reject)
ziet eruit als een snelkoppeling voor then(fulfill).catch(reject)
, maar dat is het niet en zal problemen veroorzaken als ze door elkaar worden gebruikt. Een dergelijk probleem is dat het reject
handler behandelt geen fouten uit het fulfill
handler. Hier is wat er zal gebeuren:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }, // error in the fulfill handler
error => { /* this is not called! */ });
De bovenstaande code resulteert in een afgewezen belofte omdat de fout wordt verspreid. Vergelijk het met de volgende code, wat resulteert in een vervulde belofte:
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }) // error in the fulfill handler
.catch(error => { /* handle error */ });
Een soortgelijk probleem bestaat bij het gebruik van then(fulfill, reject)
elkaar met catch(reject).then(fulfill)
, behalve bij het verspreiden van vervulde beloften in plaats van afgewezen beloften.
Synchroon gooien van functie die een belofte zou moeten opleveren
Stel je een functie als deze voor:
function foo(arg) {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
Als zo'n functie midden in een belofteketen wordt gebruikt, is er blijkbaar geen probleem:
makeSomethingAsync().
.then(() => foo('unexpectedValue'))
.catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here
Als dezelfde functie echter buiten een belofteketen wordt genoemd, wordt de fout er niet mee afgehandeld en wordt deze naar de toepassing doorgestuurd:
foo('unexpectedValue') // <-- error will be thrown, so the application will crash
.then(makeSomethingAsync) // <-- will not run
.catch(err => console.log(err)) // <-- will not catch
Er zijn 2 mogelijke oplossingen:
Retourneer een afgewezen belofte met de fout
In plaats van te gooien, doet u het volgende:
function foo(arg) {
if (arg === 'unexepectedValue') {
return Promise.reject(new Error('UnexpectedValue'))
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
Wikkel je functie in een belofteketen
Je throw
statement wordt correct gevangen als het al in een belofteketen zit:
function foo(arg) {
return Promise.resolve()
.then(() => {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
})
}
Synchrone en asynchrone bewerkingen op elkaar afstemmen
In sommige gevallen wilt u misschien een synchrone bewerking in een belofte wikkelen om herhaling in codetakken te voorkomen. Neem dit voorbeeld:
if (result) { // if we already have a result
processResult(result); // process it
} else {
fetchResult().then(processResult);
}
De synchrone en asynchrone takken van de bovenstaande code kunnen worden afgestemd door de synchrone bewerking redundant in een belofte te verpakken:
var fetch = result
? Promise.resolve(result)
: fetchResult();
fetch.then(processResult);
Wanneer u het resultaat van een asynchrone oproep in de cache opslaat, verdient het de voorkeur om de belofte te cachen in plaats van het resultaat zelf. Dit zorgt ervoor dat slechts één asynchrone bewerking nodig is om meerdere parallelle aanvragen op te lossen.
Er moet voor worden gezorgd dat waarden in de cache ongeldig worden gemaakt wanneer er zich foutcondities voordoen.
// 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;
}
Beperk een reeks tot geketende beloften
Dit ontwerppatroon is handig voor het genereren van een reeks asynchrone acties uit een lijst met elementen.
Er zijn twee varianten:
- de "toenmalige" reductie, die een ketting bouwt die blijft bestaan zolang de ketting succes ervaart.
- de "vangst" -reductie, die een ketting bouwt die blijft bestaan zolang de ketting fouten ervaart.
De "toen" reductie
Deze variant van het patroon bouwt een .then()
-keten en kan worden gebruikt voor het koppelen van animaties of het maken van een reeks afhankelijke HTTP-aanvragen.
[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
Uitleg:
- We roepen
.reduce()
op eenPromise.resolve()
en biedenPromise.resolve()
als beginwaarde. - Elk verlaagd element voegt een
.then()
aan de beginwaarde. -
reduce()
product van reduce () wordt Promise.resolve (). vervolgens (...). vervolgens (...). - We voegen handmatig een
.then(successHandler, errorHandler)
na het verkleinen, omsuccessHandler
te voeren zodra alle voorgaande stappen zijn opgelost. Als een stap zou mislukken, zouerrorHandler
uitgevoerd.
Opmerking: de "toen" -reductie is een opeenvolgende tegenhanger van Promise.all()
.
De "vangst" -reductie
Deze variant van het patroon bouwt een .catch()
-keten en kan worden gebruikt voor het sequentieel onderzoeken van een set webservers voor een gespiegelde bron totdat een werkende server wordt gevonden.
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
Uitleg:
- We roepen
.reduce()
op eenPromise.reject()
en biedenPromise.reject()
als beginwaarde. - Elk verlaagd element voegt een
.catch()
aan de beginwaarde. -
reduce()
product vanPromise.reject().catch(...).catch(...)
wordtPromise.reject().catch(...).catch(...)
. - We voegen
.then(successHandler, errorHandler)
na het verkleinen handmatig toe omsuccessHandler
te voeren zodra een van de voorgaande stappen is opgelost. Als alle stappen zouden mislukken, zouerrorHandler
uitgevoerd.
Opmerking: De "vangst" -reductie is een sequentiële tegenhanger van Promise.any()
(zoals geïmplementeerd in bluebird.js
, maar momenteel niet in native ECMAScript).
Voor iedereen met beloften
Het is mogelijk om effectief een functie ( cb
) toe te passen die een belofte teruggeeft aan elk element van een array, waarbij elk element wacht om te worden verwerkt totdat het vorige element is verwerkt.
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);
};
Dit kan nuttig zijn als u duizenden items één voor één efficiënt moet verwerken. Als je een reguliere for
lus gebruikt om de beloften te maken, worden ze allemaal in één keer gemaakt en neemt het een aanzienlijke hoeveelheid RAM-geheugen in beslag.
Opschonen uitvoeren met eindelijk ()
Er is momenteel een voorstel (nog geen onderdeel van de ECMAScript-standaard) om een finally
callback toe te voegen aan beloftes die worden uitgevoerd, ongeacht of de belofte is vervuld of afgewezen. Semantisch, dit is vergelijkbaar met de finally
clausule van de try
blok .
U gebruikt deze functionaliteit meestal voor het opschonen:
var loadingData = true;
fetch('/data')
.then(result => processData(result.data))
.catch(error => console.error(error))
.finally(() => {
loadingData = false;
});
Het is belangrijk op te merken dat de finally
callback de toestand van de belofte niet beïnvloedt. Het maakt niet uit welke waarde het retourneert, de belofte blijft in de vervulde / afgewezen staat die het eerder had. In het bovenstaande voorbeeld wordt de belofte dus opgelost met de retourwaarde van processData(result.data)
, hoewel de finally
callback undefined
geretourneerd.
Terwijl het standaardisatieproces nog steeds aan de gang is, ondersteunt uw implementatie van beloften hoogstwaarschijnlijk geen finally
callbacks uit de doos. Voor synchrone callbacks kunt u deze functionaliteit echter met een polyfill toevoegen:
if (!Promise.prototype.finally) {
Promise.prototype.finally = function(callback) {
return this.then(result => {
callback();
return result;
}, error => {
callback();
throw error;
});
};
}
Asynchrone API-aanvraag
Dit is een voorbeeld van een eenvoudige GET
API-aanroep verpakt in een belofte om te profiteren van de asynchrone functionaliteit.
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();
});
};
Meer robuuste foutafhandeling kan worden gedaan met behulp van de volgende onload
en onerror
functies.
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 / await gebruiken
Hetzelfde voorbeeld hierboven, het laden van afbeeldingen , kan worden geschreven met behulp van asynchrone functies . Dit maakt het ook mogelijk om de algemene try/catch
methode te gebruiken voor het afhandelen van uitzonderingen.
Opmerking: vanaf april 2017 ondersteunt de huidige versie van alle browsers behalve Internet Explorer async-functies .
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);
}
})();