Obietnice mają swój stan, zaczynają się jako oczekujące i mogą ustąpić:
- spełnione, co oznacza, że obliczenia zostały zakończone pomyślnie.
- odrzucono, co oznacza, że obliczenia nie powiodły się.
Funkcje obiecujące powracające funkcje nigdy nie powinny rzucać , zamiast tego powinny zwracać odrzucenia. Wyrzucenie z funkcji powrotu obietnicy zmusi cię do użycia zarówno a, jak } catch {
i a .catch
. Osoby korzystające z obiecanych interfejsów API nie oczekują, że obietnice zostaną rzucone. Jeśli nie masz pewności, jak działają asynchroniczne interfejsy API w JS - zapoznaj się z tą odpowiedzią najpierw .
1. Ładowanie DOM lub inne jednorazowe zdarzenie:
Tak więc tworzenie obietnic zazwyczaj oznacza określenie, kiedy się rozliczają - to znaczy, kiedy przechodzą do fazy spełnionej lub odrzuconej, aby wskazać, że dane są dostępne (i można uzyskać do nich dostęp .then
).
Dzięki nowoczesnym implementacjom obietnic, które wspierają Promise
konstruktora, podobnie jak natywne obietnice ES6:
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
Następnie skorzystasz z wynikowej obietnicy w następujący sposób:
load().then(function() {
// Do things after onload
});
Z bibliotekami, które obsługują odroczenie (w tym przykładzie użyjemy $ q, ale jQuery użyjemy później):
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
Lub za pomocą interfejsu jQuery, takiego jak interfejs API, umożliwiając jednokrotne zdarzenie:
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. Zwykły oddzwonienie:
Te interfejsy API są dość powszechne, ponieważ dobrze… wywołania zwrotne są częste w JS. Spójrzmy na typowy przypadek posiadania onSuccess
i onFail
:
function getUserData(userId, onLoad, onFail) { …
Dzięki nowoczesnym implementacjom obietnic, które wspierają Promise
konstruktora, podobnie jak natywne obietnice ES6:
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
Z bibliotekami, które obsługują odroczenie (użyjmy tutaj jQuery dla tego przykładu, ale użyliśmy również $ q powyżej):
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
jQuery oferuje również $.Deferred(fn)
formularz, który ma tę zaletę, że pozwala nam napisać wyrażenie, które bardzo dokładnie emuluje new Promise(fn)
formularz, w następujący sposób:
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
Uwaga: W tym miejscu wykorzystujemy fakt, że odroczone resolve
i reject
metody jQuery są „odłączalne”; to znaczy. są powiązane z instancją jQuery.Deferred (). Nie wszystkie biblioteki oferują tę funkcję.
3. Oddzwanianie w stylu węzła („nodeback”):
Odwołania zwrotne w stylu węzła (nodebacks) mają określony format, w którym wywołania zwrotne są zawsze ostatnim argumentem, a jego pierwszym parametrem jest błąd. Obiecajmy najpierw ręcznie:
getStuff("dataParam", function(err, data) { …
Do:
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
W przypadku odroczenia możesz wykonać następujące czynności (użyjmy Q w tym przykładzie, chociaż Q obsługuje teraz nową składnię, którą powinieneś preferować ):
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;
}
Ogólnie rzecz biorąc, nie powinieneś zbytnio obiecywać rzeczy, większość bibliotek obietnic, które zostały zaprojektowane z myślą o Węzle, a także natywne obietnice w Node 8+ mają wbudowaną metodę obiecujących plecaków węzłów. Na przykład
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. Cała biblioteka z wywołaniami zwrotnymi w stylu węzła:
Nie ma tutaj złotej reguły, obiecasz je jeden po drugim. Jednak niektóre implementacje obietnicy pozwalają to zrobić zbiorczo, na przykład w Bluebird, konwersja interfejsu API nodeback do interfejsu API obietnicy jest tak prosta, jak:
Promise.promisifyAll(API);
Lub z rodzimymi obietnicami w węźle :
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}), {});
Uwagi:
- Oczywiście, gdy jesteś w przewodniku
.then
, nie musisz obiecywać rzeczy. Zwrócenie obietnicy od .then
opiekuna rozwiązuje lub odrzuca wartość tej obietnicy. Rzucanie od przewodnika .then
jest również dobrą praktyką i odrzuca obietnicę - jest to słynne obietnica bezpieczeństwa rzucania.
- W rzeczywistości
onload
powinieneś użyć addEventListener
zamiast onX
.