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.

Belofte stroomdiagram

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.


Live demonstratie

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:

  1. We roepen .reduce() op een Promise.resolve() en bieden Promise.resolve() als beginwaarde.
  2. Elk verlaagd element voegt een .then() aan de beginwaarde.
  3. reduce() product van reduce () wordt Promise.resolve (). vervolgens (...). vervolgens (...).
  4. We voegen handmatig een .then(successHandler, errorHandler) na het verkleinen, om successHandler te voeren zodra alle voorgaande stappen zijn opgelost. Als een stap zou mislukken, zou errorHandler 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:

  1. We roepen .reduce() op een Promise.reject() en bieden Promise.reject() als beginwaarde.
  2. Elk verlaagd element voegt een .catch() aan de beginwaarde.
  3. reduce() product van Promise.reject().catch(...).catch(...) wordt Promise.reject().catch(...).catch(...) .
  4. We voegen .then(successHandler, errorHandler) na het verkleinen handmatig toe om successHandler te voeren zodra een van de voorgaande stappen is opgelost. Als alle stappen zouden mislukken, zou errorHandler 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);
    }

})();


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow