我正在使用JavaScript中的promises并试图宣传setTimeout函数:
function timeout(ms) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve('timeout done'); }, ms); }); } var myPromise=timeout(3000); myPromise.then(function(result) { console.log(result); // timeout done })
相当简单,但我想知道如何在诺言结算之前取消我的超时.timeout
返回Promise
对象因此我松开了对setTimeout
返回值的访问权限,并且无法通过取消超时clearTimeout
.最好的方法是什么?
顺便说一句,这没有真正的目的,我只是想知道如何处理这个问题.我也把它放在这里http://plnkr.co/edit/NXFjs1dXWVFNEOeCV1BA?p=preview
您可以做什么,您可以从您的timeout
函数返回一个取消器,并在需要时调用它.这样您就不需要存储timeoutid
全局(或外部作用域),也可以管理对函数的多个调用.函数返回的每个对象实例timeout
都有自己的取消器,可以执行取消.
function timeout(ms) { var timeout, promise; promise = new Promise(function(resolve, reject) { timeout = setTimeout(function() { resolve('timeout done'); }, ms); }); return { promise:promise, cancel:function(){clearTimeout(timeout );} //return a canceller as well }; } var timeOutObj =timeout(3000); timeOutObj.promise.then(function(result) { console.log(result); // timeout done }); //Cancel it. timeOutObj.cancel();
Plnkr
然而,PSL的答案是正确的 - 有一些警告,我会做的有点不同.
超时被清除意味着代码不会运行 - 所以我们应该拒绝承诺.
在我们的例子中,返回两件事是没有必要的,我们可以在JavaScript中修补补丁.
这里:
function timeout(ms, value) { var p = new Promise(function(resolve, reject) { p._timeout = setTimeout(function() { resolve(value); }, ms); p.cancel = function(err){ reject(err || new Error("Timeout")); clearTimeout(p._timeout); // We actually don't need to do this since we // rejected - but it's well mannered to do so }); return p; }
哪个让我们这样做:
var p = timeout(1500) p.then(function(){ console.log("This will never log"); }) p.catch(function(){ console.log("This will get logged so we can now handle timeouts!") }) p.cancel(Error("Timed out"));
人们可能对完全取消感兴趣,实际上一些图书馆直接支持这作为图书馆的一个功能.事实上,我敢说大多数人都这样做.但是,这会导致干扰问题.从这里引用KrisKowal :
我取消的立场已经发生了变化.我现在确信使用Promise抽象取消(bg:传播)本质上是不可能的,因为promises可以随时引入多个dependess和dependees.如果任何家属取消承诺,它将能够干扰未来的家属.有两种方法可以解决这个问题.一种是引入单独的取消"能力",也许作为论据传递.另一种是引入一种新的抽象,一种可能是可行的"任务",它可以取代每个任务只有一个观察者(一个随后就可以调用),而不必担心干扰.任务将支持fork()方法来创建新任务,允许另一个dependee保留任务或推迟取消.