如何重构一个使用相同函数的promise catch,但在调用函数中也是一个变量?

Posted

技术标签:

【中文标题】如何重构一个使用相同函数的promise catch,但在调用函数中也是一个变量?【英文标题】:How to refactor a promise catch that uses the same function, but also a variable in the calling one? 【发布时间】:2015-06-27 03:11:34 【问题描述】:

我使用ExpressJS 进行路由,bluebird 用于 Promises。 我对几条路线重复了以下代码,最后它们都具有相同的 .catch 函数,并以失败的 json 响应。

router.get('/', function(req, res) 
    return somePromise
    .then(function doesSomething(someVariable) 
        doSomething;
    )
    .catch(function catchesError(err) 
        return res.json( success: false );
    );
);

我想提取 catchesError 函数,但它无法使用 res 对象。

有什么建议吗?

【问题讨论】:

【参考方案1】:

只需创建一个函数并将res 对象作为参数传递并返回一个函数。

function makeErrorCatcher(res) 
    return function catchesError(err) 
        return res.json(
            success: false
        );
    

router.get('/', function (req, res) 
    return somePromise
        .then(function doesSomething(someVariable) 
            doSomething;
        )
        .catch(makeErrorCatcher(res));
);

【讨论】:

+1,尽管我推荐一个命名方案,如function makeErrorCatcher(res) return function catchesError(err) …【参考方案2】:

您可以装饰.get 以传递具有默认捕获处理程序。 (假设您对自定义路由器不感兴趣):

Object.keys(router).forEach(function(key) // for each method
    router[key+"P"] = function(path, fn) // create a decorated alt
        router[key].call(router, function(req, res, next)  // delegate
            var that = this, args = arguments;
            return Promise.try(function() // wrap to make throw safe
                return fn.apply(that, args); // delegation
            ).catch(function catchesError(err)
                // LOG YOUR ERRORS, DON'T CATCH ALL
                return res.json( success: false );
            );
        );
    ;
);

这会让你这样做:

router.getP('/', function(req, res) 
    return somePromise.then(function doesSomething(someVariable) 
        doSomething;
    );
);

现在它将自动捕获错误并发送适当的 JSON。消除重复或完全忘记错误的可能性。

【讨论】:

【参考方案3】:

很像 Ben Fortune 的解决方案,使用bind()

function catchesError(res, err) 
    return res.json( success: false );


router.get('/', function(req, res) 
    return somePromise
    .then(function doesSomething(someVariable) 
        doSomething;
    )
    .catch(catchesError.bind(null, res));
);

如果您在上课,请将 null 替换为 this

【讨论】:

与 Ben Fortune 的解决方案相比,使用 .bind 的优缺点是什么? 先生。财富的解决方案基本上是绑定的。当您不确定bind() 是否可用时,这就是您使用的——用于浏览器的代码。在 Node.js 中,我们知道该功能将可用。无需自己动手。 bind() 还支持附加this 和开箱即用的可变数量的参数。它在许多其他情况下很有用:计时器回调和事件处理程序是最明显的。【参考方案4】:

如果您不打算使用承诺链,您可以添加一个附加catch 处理程序的catcher 函数:

function catcher(promise, req, res) 
    promise.catch(function catchesError(err) 
        return res.json( success: false );
    );
    return promise;


router.get('/', function(req, res) 
    return catcher(somePromise, req, res)
    .then(function doesSomething(someVariable) 
        doSomething;
    );
);

但是,如果您想受益于令人敬畏的承诺链机制,那么您需要手动调用 catch 处理程序以确保它是链中的最后一个:

function makeCatchHandler(res) 
    return function(err) 
        return res.json( success: false );
    ;


router.get('/', function(req, res) 
    return catcher(somePromise, req, res)
    .then(function doesSomething(someVariable) 
        doSomething;
    ).catch(makeCatchHandler(res));
);

【讨论】:

以上是关于如何重构一个使用相同函数的promise catch,但在调用函数中也是一个变量?的主要内容,如果未能解决你的问题,请参考以下文章

处理类构造函数中的承诺错误[重复]

如何使用 Promise Kit 调用递归函数?

ES6知识点整理之----async----语法

重构:从Promise到Async/Await

Android代码如何重构

Android代码如何重构