【发布时间】:2019-01-28 11:05:48
【问题描述】:
这里有一个例子,希望能更容易理解这个问题。
var listen = document.querySelector("#listen"),
cancel = document.querySelector("#cancel"),
submit = document.querySelector("#submit");
var promiseResolve = null;
listen.addEventListener("click", startListening);
cancel.addEventListener("click", abort);
submit.addEventListener("click", onSubmitClick);
submit.disabled = true;
function startListening() {
submit.disabled = false;
listen.disabled = true;
new Promise(function(resolve) {
promiseResolve = resolve;
}).then(onSubmit);
}
function abort() {
listen.disabled = false;
submit.disabled = true;
promiseResolve = null;
}
function onSubmitClick() {
if (promiseResolve) promiseResolve();
}
function onSubmit() {
console.log("Done");
abort();
}
<button id="listen">Listen</button>
<button id="submit">Submit</button>
<button id="cancel">Cancel</button>
在上面的脚本中,有一个动作 (listen) 将在 Promise 的帮助下启用另一个动作 (submit)。但是可以使用cancel 操作取消该流程,将大部分代码返回到其原始状态。 cancel 操作仅将 Promise 的 resolve 的引用设置为 null,这意味着承诺将永远处于不确定状态,因为它永远不会被解决或拒绝。所以这些是我的问题:
- 这种方法正确吗?
- 是否会多次执行此操作,占用同样大量的资源?
- 我是否还应该保留对拒绝函数的引用并在
cancel操作中调用它?
我知道在上面的例子中,同样的结果可以通过
使用boolean 标志检查是否已按下监听按钮
在提交之前,但就像我说的这只是一个例子,所以我
可以更容易地解释问题。
【问题讨论】:
-
我相信理论上它应该被 GC 处理。但它使用 Promises 来完成它们的设计目的。要真正获得 Promise 的好处,最好考虑如何以同步方式执行此操作,然后以这种方式编写代码。例如。你可以让你的 startListening 变成一个承诺,然后你把它放在一个循环中,对于中止我会生成一个自定义错误,比如
EAbort。经常有很多关于可取消承诺的讨论,但我不确定它处于什么状态。我相信谷歌不喜欢这个想法,这可能是因为可取消的承诺有点像任务终止。 -
查看您的代码,您不再有引用,您这样做了 ->
promiseResolve = null;如果引用无法返回根/全局,则 GC 通过查看引用来工作,附注。计时器等也是全球性的。然后垃圾收集器将处理。 GC 甚至足够聪明地 GCa = b; b = a,这是 C++ 领域中interfaces之类的引用计数内存管理的限制。 -
@Keith 我明白你在说什么,请查看我对答案的评论以了解我的问题。
标签: javascript ecmascript-6 promise