Le promesse hanno uno stato, iniziano come in sospeso e possono accontentarsi di:
- significato soddisfatto che il calcolo è stato completato con successo.
- rifiutato significa che il calcolo non è riuscito.
Le funzioni di ritorno promettenti non dovrebbero mai essere lanciate , dovrebbero invece restituire rifiuti. Lanciare da una funzione di ritorno promessa ti costringerà a usare sia a } catch {
che a .catch
. Le persone che utilizzano API promisificate non si aspettano che promettano di lanciare. Se non sei sicuro di come funzionano le API asincrone in JS, consulta prima questa risposta .
1. Caricamento DOM o altro evento singolo:
Quindi, creare promesse in genere significa specificare quando si stabiliscono - ciò significa quando si spostano nella fase adempiuta o respinta per indicare che i dati sono disponibili (e sono accessibili con .then
).
Con le moderne implementazioni delle promesse che supportano il Promise
costruttore come le promesse ES6 native:
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
Utilizzeresti quindi la promessa risultante in questo modo:
load().then(function() {
// Do things after onload
});
Con le librerie che supportano il differito (Usiamo $ q per questo esempio qui, ma useremo anche jQuery in seguito):
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
O con un'API jQuery come, collegandosi a un evento che si verifica una volta:
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. Richiamata semplice:
Queste API sono piuttosto comuni poiché bene ... i callback sono comuni in JS. Diamo un'occhiata al caso comune di avere onSuccess
e onFail
:
function getUserData(userId, onLoad, onFail) { …
Con le moderne implementazioni delle promesse che supportano il Promise
costruttore come le promesse ES6 native:
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
Con le librerie che supportano il differito (Usiamo jQuery per questo esempio qui, ma abbiamo anche usato $ q sopra):
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
jQuery offre anche un $.Deferred(fn)
modulo, che ha il vantaggio di permetterci di scrivere un'espressione che emula molto da vicino il new Promise(fn)
modulo, come segue:
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
Nota: qui sfruttiamo il fatto che i metodi resolve
e i reject
metodi differiti di un jQuery sono "staccabili"; vale a dire. sono associati all'istanza di un jQuery.Deferred (). Non tutte le librerie offrono questa funzione.
3. Callback stile nodo ("nodeback"):
I callback (nodiback) in stile nodo hanno un formato particolare in cui i callback sono sempre l'ultimo argomento e il suo primo parametro è un errore. Promettiamo prima uno manualmente:
getStuff("dataParam", function(err, data) { …
Per:
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
Con i rinvii puoi fare quanto segue (usiamo Q per questo esempio, sebbene Q ora supporti la nuova sintassi che dovresti preferire ):
function getStuffAsync(param) {
var d = Q.defer();
getStuff(param, function(err, data) {
if (err !== null) d.reject(err);
else d.resolve(data);
});
return d.promise;
}
In generale, non dovresti promettere le cose manualmente troppo, la maggior parte delle librerie di promesse progettate pensando a Nodo, così come le promesse native in Nodo 8+ hanno un metodo incorporato per la promozione di nodi di nodo. Per esempio
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. Un'intera libreria con richiamate in stile nodo:
Non esiste una regola d'oro qui, li prometti uno per uno. Tuttavia, alcune implementazioni promesse ti consentono di farlo in blocco, ad esempio in Bluebird, convertire un'API nodeback in un'API promessa è semplice come:
Promise.promisifyAll(API);
O con promesse native in Node :
const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
.reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
Appunti:
- Certo, quando sei in un
.then
gestore non devi promettere cose. Restituzione di una promessa da a.then
gestore risolverà o rifiuterà con il valore di quella promessa. Lanciare da un .then
gestore è anche una buona pratica e rifiuterà la promessa - questa è la famosa promessa di sicurezza.
- In un
onload
caso reale , dovresti usare addEventListener
piuttosto che onX
.