To nie jest prawdziwy problem, po prostu próbuję zrozumieć, jak powstają obietnice.
Muszę zrozumieć, jak złożyć obietnicę dotyczącą funkcji, która nic nie zwraca, na przykład setTimeout.
Załóżmy, że mam:
function async(callback){
setTimeout(function(){
callback();
}, 5000);
}
async(function(){
console.log('async called back');
});
Jak utworzyć obietnicę, która async
może zostać zwrócona, gdy setTimeout
będzie gotowa callback()
?
Przypuszczałem, że zawinięcie go gdzieś zabierze:
function setTimeoutReturnPromise(){
function promise(){}
promise.prototype.then = function() {
console.log('timed out');
};
setTimeout(function(){
return ???
},2000);
return promise;
}
Ale nie mogę myśleć poza tym.
javascript
settimeout
promise
laggingreflex
źródło
źródło
async function async(){...}
Odpowiedzi:
Aktualizacja (2017)
Tutaj w 2017 obietnice są wbudowane w JavaScript, zostały dodane zgodnie ze specyfikacją ES2015 (wypełniacze są dostępne dla przestarzałych środowisk, takich jak IE8-IE11). Składnia, z którą poszli, wykorzystuje wywołanie zwrotne, które przekazujesz do
Promise
konstruktora (Promise
executora ), który otrzymuje funkcje do rozwiązywania / odrzucania obietnicy jako argumenty.Po pierwsze, ponieważ
async
teraz ma znaczenie w JavaScript (mimo że jest to słowo kluczowe tylko w niektórych kontekstach), zamierzam użyćlater
jako nazwy funkcji, aby uniknąć nieporozumień.Podstawowe opóźnienie
Używając natywnych obietnic (lub wiernego polyfill), wyglądałoby to tak:
function later(delay) { return new Promise(function(resolve) { setTimeout(resolve, delay); }); }
Zauważ, że zakłada się, że wersja
setTimeout
jest zgodna z definicją dla przeglądarek, w którejsetTimeout
nie przekazuje żadnych argumentów do wywołania zwrotnego, chyba że podasz je po interwale (może to nie być prawdą w środowiskach innych niż przeglądarka i nie było prawda w Firefoksie, ale jest teraz; jest prawdą w Chrome, a nawet w IE8).Podstawowe opóźnienie z wartością
Jeśli chcesz, aby funkcja opcjonalnie przekazywała wartość rozdzielczości, w dowolnej dość nowoczesnej przeglądarce, która umożliwia podanie dodatkowych argumentów
setTimeout
po opóźnieniu, a następnie przekazanie ich do wywołania zwrotnego po wywołaniu, możesz to zrobić (bieżące przeglądarki Firefox i Chrome; IE11 + , prawdopodobnie Edge; nie IE8 ani IE9, nie mam pojęcia o IE10):function later(delay, value) { return new Promise(function(resolve) { setTimeout(resolve, delay, value); // Note the order, `delay` before `value` /* Or for outdated browsers that don't support doing that: setTimeout(function() { resolve(value); }, delay); Or alternately: setTimeout(resolve.bind(null, value), delay); */ }); }
Jeśli używasz funkcji strzałek ES2015 +, może to być bardziej zwięzłe:
function later(delay, value) { return new Promise(resolve => setTimeout(resolve, delay, value)); }
lub nawet
const later = (delay, value) => new Promise(resolve => setTimeout(resolve, delay, value));
Opóźnienie z możliwością anulowania z wartością
Jeśli chcesz umożliwić anulowanie limitu czasu, nie możesz po prostu zwrócić obietnicy od
later
, ponieważ obietnic nie można anulować.Ale możemy łatwo zwrócić obiekt z
cancel
metodą i akcesorium dla obietnicy i odrzucić obietnicę w przypadku anulowania:const later = (delay, value) => { let timer = 0; let reject = null; const promise = new Promise((resolve, _reject) => { reject = _reject; timer = setTimeout(resolve, delay, value); }); return { get promise() { return promise; }, cancel() { if (timer) { clearTimeout(timer); timer = 0; reject(); reject = null; } } }; };
Przykład na żywo:
const later = (delay, value) => { let timer = 0; let reject = null; const promise = new Promise((resolve, _reject) => { reject = _reject; timer = setTimeout(resolve, delay, value); }); return { get promise() { return promise; }, cancel() { if (timer) { clearTimeout(timer); timer = 0; reject(); reject = null; } } }; }; const l1 = later(100, "l1"); l1.promise .then(msg => { console.log(msg); }) .catch(() => { console.log("l1 cancelled"); }); const l2 = later(200, "l2"); l2.promise .then(msg => { console.log(msg); }) .catch(() => { console.log("l2 cancelled"); }); setTimeout(() => { l2.cancel(); }, 150);
Oryginalna odpowiedź z 2014 r
Zwykle będziesz mieć bibliotekę obietnic (taką, którą napiszesz sam, lub jedną z kilku dostępnych). Ta biblioteka zazwyczaj będzie zawierała obiekt, który możesz utworzyć i później „rozwiązać”, a obiekt ten będzie miał „obietnicę”, którą możesz z niego uzyskać.
Wtedy
later
wyglądałby mniej więcej tak:function later() { var p = new PromiseThingy(); setTimeout(function() { p.resolve(); }, 2000); return p.promise(); // Note we're not returning `p` directly }
W komentarzu do pytania zapytałem:
i Ty powiedziałeś
Aby pomóc w zrozumieniu, oto bardzo podstawowy przykład, który nie jest zdalnie zgodny z obietnicą A: kopia na żywo
<!DOCTYPE html> <html> <head> <meta charset=utf-8 /> <title>Very basic promises</title> </head> <body> <script> (function() { // ==== Very basic promise implementation, not remotely Promises-A compliant, just a very basic example var PromiseThingy = (function() { // Internal - trigger a callback function triggerCallback(callback, promise) { try { callback(promise.resolvedValue); } catch (e) { } } // The internal promise constructor, we don't share this function Promise() { this.callbacks = []; } // Register a 'then' callback Promise.prototype.then = function(callback) { var thispromise = this; if (!this.resolved) { // Not resolved yet, remember the callback this.callbacks.push(callback); } else { // Resolved; trigger callback right away, but always async setTimeout(function() { triggerCallback(callback, thispromise); }, 0); } return this; }; // Our public constructor for PromiseThingys function PromiseThingy() { this.p = new Promise(); } // Resolve our underlying promise PromiseThingy.prototype.resolve = function(value) { var n; if (!this.p.resolved) { this.p.resolved = true; this.p.resolvedValue = value; for (n = 0; n < this.p.callbacks.length; ++n) { triggerCallback(this.p.callbacks[n], this.p); } } }; // Get our underlying promise PromiseThingy.prototype.promise = function() { return this.p; }; // Export public return PromiseThingy; })(); // ==== Using it function later() { var p = new PromiseThingy(); setTimeout(function() { p.resolve(); }, 2000); return p.promise(); // Note we're not returning `p` directly } display("Start " + Date.now()); later().then(function() { display("Done1 " + Date.now()); }).then(function() { display("Done2 " + Date.now()); }); function display(msg) { var p = document.createElement('p'); p.innerHTML = String(msg); document.body.appendChild(p); } })(); </script> </body> </html>
źródło
const setTimeoutAsync = (cb, delay) => new Promise((resolve) => { setTimeout(() => { resolve(cb()); }, delay); });
Możemy przekazać niestandardowe 'cb fxn' takie jak ten 👆🏽
źródło
To nie jest odpowiedź na pierwotne pytanie. Ale ponieważ oryginalne pytanie nie jest problemem w świecie rzeczywistym, nie powinno być problemem. Próbowałem wyjaśnić znajomemu, czym są obietnice w JavaScript i jaka jest różnica między obietnicą a wywołaniem zwrotnym.
Poniższy kod służy jako wyjaśnienie:
//very basic callback example using setTimeout //function a is asynchronous function //function b used as a callback function a (callback){ setTimeout (function(){ console.log ('using callback:'); let mockResponseData = '{"data": "something for callback"}'; if (callback){ callback (mockResponseData); } }, 2000); } function b (dataJson) { let dataObject = JSON.parse (dataJson); console.log (dataObject.data); } a (b); //rewriting above code using Promise //function c is asynchronous function function c () { return new Promise(function (resolve, reject) { setTimeout (function(){ console.log ('using promise:'); let mockResponseData = '{"data": "something for promise"}'; resolve(mockResponseData); }, 2000); }); } c().then (b);
JsFiddle
źródło