在观看Douglas Crokfrod 关于 monads 和 promises 的演讲时,我对 52:40 提出的一个问题感兴趣。如何使用 Monads 实现看门狗计时器,以便在调用失败函数之前,可以保持承诺或仅在未决状态中存在一段可定义的时间长度。这种模式是否有一个普遍接受的名称?
2 回答
不是,杰森。查看 Crockford 在 GitHub 上的实现,它没有适合该行为的钩子。
也就是说,在典型的 Promise 范式中,有比 Crockford 代码授予的选项更多的选项。
查看 AJAX 库。尽管很多人不知道,但很多 AJAX 库(包括 jQuery)都会返回 Promise。
要在他的代码中执行此操作,您可以挂钩一个子句,该子句具有一个计时器,该计时器.break
是基于与承诺的参数一起提交的时间。
否则,您可以执行以下操作:
var vow = VOW.make(),
last_promise = vow.when()
.when()
.when()
.when() /*...*/;
(function () {
var vow = VOW.make(),
time_over = false,
time_limit = 30 * 1000,
timer_handle,
success = function (value) {
if (time_over) { vow["break"]("Time's up!"); }
else {
clearInterval(timer_handle);
vow.keep(value);
}
};
trailing_promise.when(success, /* fail */);
return vow.promise;
}()).when(/* ... */)
.when()
.when();
我认为,类似的东西应该适用于那里给出的东西。
就个人而言,在看过演讲并阅读了他的实现之后,我认为我更喜欢承诺保留他们的线性队列功能(done
,fail
或success/fail
或ready/fail
或其他),但我见过的大多数库都制作了时间队列(when
,,next
等)与诺言分开。
所以这里有两个相互竞争的队列,真的。一个订阅事件的地方(比如.addEventListener
:当动作发生时,所有的监听器同时被调用),一个订阅下一个结果的最终返回(比如收听正在订阅的东西)一个事件列表器)。
在 Crockford 的最小实现中,更像是只能有一个监听器,然后订阅者监听前一个订阅者的最后一个订阅者...
...并且将多个指令链接到同一队列中的唯一方法是缓存返回:
var level_0 = VOW.make(),
level_1 = level_0.when(/* ... , ... */),
level_2 = level_1.when(/* ... , ... */);
level_1.when(/* more stuff */);
level_1.when(/* even more */);
level_2.when()
.when()
.when();
// ...eventually.......
level_0.keep("stuff");
我一直在玩 jQuery 的 Deferred 方法(虽然我找不到语句,但我认为它是单子的),看起来这会起作用(演示)(这看起来太容易了)
function watchdog(promise, time) {
setTimeout(function() {
promise.abort();
}, time);
};
使用JSFiddle中的Ajax 测试挂钩的示例:
console.log("Waiting 2,000ms for something we think will take 3,000ms to return");
watchdog(
$.post('/echo/html/', { delay: 3 })
.done(function() {console.log("Got It!");})
.fail(function() {console.log('took too long (but I knew that)!');})
.always(function() {console.log('Cleaning up no matter what');})
, 2000);
console.log("Waiting 3,000ms for something we think will take 2,000ms to return");
watchdog(
$.post('/echo/html/', { delay: 2 })
.done(function() {console.log("Got It (but I knew that)!");})
.fail(function() {console.log('took too long!');})
.always(function() {console.log('Cleaning up no matter what');})
, 3000);
这是生成的日志:
Waiting 2,000ms for something we think will take 3,000ms to return
Waiting 3,000ms for something we think will take 2,000ms to return
took too long (but I knew that)!
Cleaning up no matter what
Got It (but I knew that)!
Cleaning up no matter what