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

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

本文关键字:方法 承诺 返回 转换 回调      更新时间:2023-09-26

我试图编写一个函数,执行异步任务并返回一个承诺,同时确保在任何回调完成后发生清理。然而,要做到这一点,我似乎需要提前知道回调,这样我就可以确保它在清理发生之前发生。

目前,函数的一般结构是这样的:

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

如果可能的话,我如何构建我的方法来实现我的目标?还是说我现在所能做的就是最好的?

我有一种感觉,我可以使用延迟来完成我的目标,但我不知道如何设置它来实现这个目标。

我试图开发的API是供那些不一定了解异步方法复杂性的用户使用的,所以我想尽可能地隐藏它。

您所拥有的是处理器模式。这是你自己想出来的小道具:)

"传入"回调是必要的,因为它创建了作用域,这有效地启用了清理。你可以通过回调返回一个承诺来知道它是如何"完成"的。你需要一个作用域的事实是基本的,因为它是我们…范围清理。通过作用域(RAII)将资源分配绑定到实例化是一种非常有用的技术。

我会这样做:

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

这实际上是你已经拥有的。

正如评论所建议的,bluebird的using是一个非常有用的抽象,它返回的处理器为您提供了大量清理和清除大量类型错误的能力。我强烈推荐它(尽管我显然有偏见)。