Это не настоящая проблема, я просто пытаюсь понять, как создаются обещания.
Мне нужно понять, как дать обещание функции, которая ничего не возвращает, например setTimeout.
Предположим, у меня есть:
function async(callback){
setTimeout(function(){
callback();
}, 5000);
}
async(function(){
console.log('async called back');
});
Как создать обещание, которое async
может вернуться после того, setTimeout
как готово callback()
?
Я предполагал, что упаковка приведет меня куда-нибудь:
function setTimeoutReturnPromise(){
function promise(){}
promise.prototype.then = function() {
console.log('timed out');
};
setTimeout(function(){
return ???
},2000);
return promise;
}
Но я не могу думать дальше этого.
javascript
settimeout
promise
отстающий рефлекс
источник
источник
async function async(){...}
Ответы:
Обновление (2017 г.)
Здесь, в 2017 году, обещания встроены в JavaScript, они были добавлены спецификацией ES2015 (полифиллы доступны для устаревших сред, таких как IE8-IE11). Синтаксис, который они использовали, использует обратный вызов, который вы передаете в
Promise
конструктор (Promise
исполнитель ), который получает функции для разрешения / отклонения обещания в качестве аргументов.Во-первых, поскольку
async
теперь имеет значение в JavaScript (хотя это всего лишь ключевое слово в определенных контекстах), я собираюсь использоватьlater
в качестве имени функции, чтобы избежать путаницы.Базовая задержка
При использовании собственных обещаний (или верного полифилла) это будет выглядеть так:
function later(delay) { return new Promise(function(resolve) { setTimeout(resolve, delay); }); }
Обратите внимание, что это предполагает версию
setTimeout
, совместимую с определением для браузеров, гдеsetTimeout
не передаются никакие аргументы обратному вызову, если вы не дадите их после интервала (это может быть неверно в средах, отличных от браузера, и раньше не было правда в Firefox, но есть сейчас; это правда в Chrome и даже в IE8).Базовая задержка со значением
Если вы хотите, чтобы ваша функция опционально передавала значение разрешения в любом не очень современном браузере, который позволяет вам давать дополнительные аргументы
setTimeout
после задержки, а затем передает их в обратный вызов при вызове, вы можете сделать это (текущие Firefox и Chrome; IE11 + , предположительно Edge; не IE8 или IE9, не знаю об 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); */ }); }
Если вы используете стрелочные функции ES2015 +, это может быть более кратко:
function later(delay, value) { return new Promise(resolve => setTimeout(resolve, delay, value)); }
или даже
const later = (delay, value) => new Promise(resolve => setTimeout(resolve, delay, value));
Аннулируемая задержка со стоимостью
Если вы хотите, чтобы можно было отменить тайм-аут, вы не можете просто вернуть обещание из
later
, потому что обещания не могут быть отменены.Но мы можем легко вернуть объект с помощью
cancel
метода и метода доступа для обещания и отклонить обещание при отмене: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 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);
Оригинальный ответ от 2014 г.
Обычно у вас есть библиотека обещаний (одна, которую вы пишете сами, или одна из нескольких). В этой библиотеке обычно есть объект, который вы можете создать, а затем «разрешить», и этот объект будет иметь «обещание», которое вы можете получить от него.
Тогда
later
будет выглядеть примерно так:function later() { var p = new PromiseThingy(); setTimeout(function() { p.resolve(); }, 2000); return p.promise(); // Note we're not returning `p` directly }
В комментарии к вопросу я спросил:
и ты сказал
Чтобы помочь этому пониманию, вот очень простой пример, который удаленно не совместим с Promises-A: Live Copy
<!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>
источник
const setTimeoutAsync = (cb, delay) => new Promise((resolve) => { setTimeout(() => { resolve(cb()); }, delay); });
Мы можем передать собственный 'cb fxn', как этот 👆🏽
источник
Это не ответ на исходный вопрос. Но, поскольку исходный вопрос не является реальной проблемой, он не должен быть проблемой. Я попытался объяснить другу, что такое обещания в JavaScript и разница между обещанием и обратным вызовом.
Код ниже служит объяснением:
//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
источник