Javascript 将带有回调的方法转换为返回带有清除的承诺的方法
我正在尝试编写一个函数,该函数执行异步任务并返回承诺,同时确保在完成任何回调后进行清理。然而,要做到这一点,我似乎需要提前知道回调,以便确保它在清理之前发生 目前,该函数的总体结构如下所示:Javascript 将带有回调的方法转换为返回带有清除的承诺的方法,javascript,callback,promise,q,Javascript,Callback,Promise,Q,我正在尝试编写一个函数,该函数执行异步任务并返回承诺,同时确保在完成任何回调后进行清理。然而,要做到这一点,我似乎需要提前知道回调,以便确保它在清理之前发生 目前,该函数的总体结构如下所示: function doSomethingWithResourceAsync(someParameter, usePreparedResourceCb) { var resource = acquireResource(someParameter); return prepareResourc
function doSomethingWithResourceAsync(someParameter, usePreparedResourceCb) {
var resource = acquireResource(someParameter);
return prepareResourceAsync(resource)
.then(usePreparedResourceCb)
.finally(doCleanup);
function doCleanup() {
releaseResource(resource);
}
}
function doSomethingWithResourceHopefullyAsync(myParameter) {
var resource = acquireResource(someParameter);
return prepareResourceAsync(resource)
.finally(doCleanup); // uh oh
function doCleanup() {
releaseResource(resource);
}
}
doSomethingWithResourceHopefullyAsync(myParameter)
.then(myCallback) // too bad, already cleaned up
.then(andSoOn);
称之为,我会这样做:
doSomethingWithResourceAsync(myParameter, myCallback)
.then(andSoOn);
function myCallback(proxyObj) {
return doMagicAsync(proxyObj);
}
这是我能让它工作的唯一方法
但是,我想用一种方式来编写它,即我可以链接回调,而不必传递清除回调。所以我想这样称呼它:
function doSomethingWithResourceAsync(someParameter, usePreparedResourceCb) {
var resource = acquireResource(someParameter);
return prepareResourceAsync(resource)
.then(usePreparedResourceCb)
.finally(doCleanup);
function doCleanup() {
releaseResource(resource);
}
}
function doSomethingWithResourceHopefullyAsync(myParameter) {
var resource = acquireResource(someParameter);
return prepareResourceAsync(resource)
.finally(doCleanup); // uh oh
function doCleanup() {
releaseResource(resource);
}
}
doSomethingWithResourceHopefullyAsync(myParameter)
.then(myCallback) // too bad, already cleaned up
.then(andSoOn);
但是,这不起作用,因为清理是在myCallback
获得控制权并把事情搞砸之前进行的
如果可能,我如何构建我的方法来实现我的目标?还是我能为这种情况做的最好?
我有一种感觉,我可以利用延迟来实现我的目标,但我不知道如何设置它来实现这一目标
我试图开发的API将被那些不一定知道异步方法的复杂性的用户所使用,因此我想尽可能地隐藏它们。您所拥有的是。你自己想出来的道具:)
“传递”回调是必要的,因为它创建了一个有效启用清理的范围。通过返回承诺,您将知道回调是如何“完成”的。事实上,你需要一个范围是基本的,因为它是什么,以及。。。确定清理范围。通过作用域(RAII)将资源分配绑定到实例化是一种非常有用的技术
我会这样做:
function withResource(handler){
return acquireResource(). // important to return to chain, like your code
then(handler).finally(cleanup);
}
这实际上就是你已经拥有的
正如评论所暗示的那样,bluebird的
使用
是一个非常有用的抽象,它返回的处理器为您提供了大量清理和清理大量类型错误的能力。我强烈推荐它(尽管我显然有偏见)。使用蓝鸟而不是Q,你可以使用使用:这在将来可能非常有用,谢谢你向我指出。很好地自己找到了这个模式:)你能扩展你的例子,说明需要清理的地方吗,它需要如何等待回调
(或者:如果过早清理,回调
中有什么不起作用)?有一种模式可以解决这个问题,但我需要详细说明您的问题。@Bergi:这是Node应用程序的一部分。在某些情况下,它只是用于日志记录。在其他实例中,它用于启动子进程(和日志记录)。在我的用例中,子进程必须运行才能使回调工作。当我提到传递回调时,我指的不是处理程序(在我的示例中是cb()
函数),而是doCleanup()
函数。我不能完全相信所有调用代码都会记得总是在处理程序中调用cleanup函数。但很高兴看到你同意我的决定。回想起来,我认为这确实是最干净的方法。实际函数的名称已经暗示它将从头到尾做一些事情。说“完成这项工作,然后再做这项工作”并期望它能工作是没有意义的。确切地说,你必须以某种方式定义“开始”和“完成”,你也可以用一个范围来做,这意味着你永远不会忘记自己做清理。这在许多编程语言中都是基础,很有趣的是,看到一些语言在其核心中集成了该功能,比如C#的async使用
方案和Python 3.5的async使用
。在JavaScript中使用这种资源管理是很好的,但遗憾的是,我认为我们还没有做到这一点——当async/await明年登陆时(希望如此),我们将有更令人信服的能力:)