如何从setTimeout作出承诺
这不是一个现实世界的问题,我只是想了解如何创造承诺。
我需要了解如何为不返回任何内容的函数做出承诺,比如setTimeout。
假设我有:
function async(callback){ setTimeout(function(){ callback(); }, 5000); } async(function(){ console.log('async called back'); });
如何创build一个承诺, async
可以在setTimeout
准备好callback()
之后返回?
我想包裹它会带我到某个地方:
function setTimeoutReturnPromise(){ function promise(){} promise.prototype.then = function() { console.log('timed out'); }; setTimeout(function(){ return ??? },2000); return promise; }
但我无法超越这个想法。
更新 :在2017年,Promises被embedded到JavaScript中,它们被ES2015规范添加(polyfills可用于过时的环境,如IE8-IE11)。 它们的语法使用一个callback函数传递给Promise
构造函数( Promise
executor ),该函数接收parsing/拒绝promise的函数作为参数。
首先,由于async
现在在JavaScript中有一个意义 (即使它在某些上下文中只是一个关键字),我将later
使用它作为函数的名称以避免混淆。
使用本地的承诺(或忠实的polyfill)它看起来像这样:
function later(delay) { return new Promise(function(resolve) { setTimeout(resolve, delay); }); }
请注意,假定setTimeout
的版本符合浏览器的定义,其中setTimeout
不会将任何parameter passing给callback,除非您在时间间隔之后提供它们(在非浏览器环境中可能不是这样,并且没有使用在Firefox上是真实的,但是现在;在Chrome上,甚至在IE8上也是如此)。
如果你想让你的函数有select地传递一个分辨率值,那么在任何模糊的现代浏览器上,你可以在延迟之后给setTimeout
额外的参数,然后在被调用的时候传递给callback函数,你可以这样做(当前的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,可以更简洁:
function later(delay, value) { return new Promise(resolve => setTimeout(resolve, delay, value)); }
甚至
const later = (delay, value) => new Promise(resolve => setTimeout(resolve, delay, value));
来自2014年的原始答复 :
通常你会有一个承诺库(你自己写的,或者其中的一个)。 这个库通常会有一个你可以创build的对象,然后“解决”,而这个对象将会有一个你可以从中获得的“承诺”。
然后,往往会看起来像这样:
function later() { var p = new PromiseThingy(); setTimeout(function() { p.resolve(); }, 2000); return p.promise(); // Note we're not returning `p` directly }
在对这个问题的评论中,我问道:
你想创build自己的承诺库吗?
你说
我不是,但我想现在这其实是我想了解的。 图书馆如何做到这一点
为了帮助理解,下面是一个非常基本的例子,它不是远程Promises-A compliant: 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>