将带有回调的方法转换为 returns 带有清理的承诺

Convert a method with a callback to one that returns a promise with cleanup

我正在尝试编写一个函数来执行异步任务和 returns 承诺,同时确保在完成任何回调后进行清理。然而,要做到这一点,我似乎需要提前知道回调,这样我才能确保它在清理发生之前发生。

目前,函数的一般结构如下所示:

function doSomethingWithResourceAsync(someParameter, usePreparedResourceCb) {
    var resource = acquireResource(someParameter);
    return prepareResourceAsync(resource)
        .then(usePreparedResourceCb)
        .finally(doCleanup);

    function doCleanup() {
        releaseResource(resource);
    }
}

要调用它,我会这样做:

doSomethingWithResourceAsync(myParameter, myCallback)
    .then(andSoOn);

function myCallback(proxyObj) {
    return doMagicAsync(proxyObj);
}

这是我让它工作的唯一方法。

但是,我想以一种可以链接回调的方式编写它,而不必传递清理回调。所以我想这样称呼它:

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 获得控制权并把事情搞砸之前。

如果可能的话,我该如何构建我的方法来实现我的目标?或者我能为这种情况做些什么?

我觉得我可以使用 deferreds 来实现我的目标,但我不知道如何设置它来完成这项工作。

我正在尝试开发的 API 供不一定了解异步方法的复杂性的用户使用,因此我想尽可能地隐藏它。

你拥有的是。自己解决问题的道具:)

"Passing" 中的回调是 必需的 ,因为它创建了一个 scope,它有效地启用了清理。你会知道回调是如何 "done" 通过它返回一个承诺。您需要范围的事实是 基础 ,因为它很好... scopes 清理。通过作用域 (RAII) 将资源分配绑定到实例化对于您正在做的事情来说是一种有用的技术。

我会做类似的事情:

function withResource(handler){
    return acquireResource(). // important to return to chain, like your code
           then(handler).finally(cleanup);
}

这实际上是您已有的。

正如评论所暗示的那样,bluebird 的 using 是一个非常有用的抽象,它 returns 处理器可以为您提供强大的清理功能并清除大量类型错误。我强烈推荐它(虽然我显然有偏见)。