promise - 不解决或拒绝 promise 是否安全

标签 promise bluebird

想象一个带有路由的 Web 应用程序,它需要在继续之前检查用户是否被允许访问给定的资源。 “已验证”检查依赖于数据库调用。

在每条 route ,我可能有:

authorizeOwnership(req, res)
.then(function() {
    // do stuff
    res.send(200, "Yay");
});

我想要 authorizeOwnership()函数来处理 403(访问被拒绝)和 500(例如数据库查询错误)响应,以便每个路由不需要明确地这样做。

我有一个可以查询数据库以检查所有权的函数。
function confirmOwnership(resourceId, userId) {
    // SequelizeJS... returns a bluebird promise
    return Resource.find({
        where: {id: resourceId, userId: userId}
    })
    .then(function(resource) {
        if(!resource) {
            return null; // no match for this resource id + user id
        } else {
            return resource;
        }
    });
}

然后在 authorizeOwnership 中使用它:
function authorizeOwnership(req, res) {
    var rid      = parseInt(req.params.rid, 10),
        userId   = parseInt(req.authInfo.userid, 10);

    return new Promise(function(resolve, reject) {
        confirmOwnership(rid, userId)
        .then(function(resource) {
            if(resource === null) {
                res.send(403, "Forbidden");
                // Note: we don't resolve; outer handler will not be called
            } else {
                resolve(resource);
            }
        })
        .catch(function(err) {
            console.log(err);
            res.send(500, "Server error");
            // Note: we don't resolve; outer handler will not be called
        });
    });
}

在这种情况下,我故意不打电话reject()resolve()在一些代码路径中。如果我这样做,那么我的“外部”路由逻辑(调用 authorizeOwnership() 的代码)变得更加复杂,因为它必须处理错误(使用 .catch() 或使用 null checkin .then() )。

不过有两件事让我有点紧张:
  • authorizeOwnership()返回的promise可以吗?在错误情况下永远无法解决?它会导致延迟或内存泄漏吗?
  • 解析 confirmOwnership() 在逻辑上是否合理?使用 null 表示“找不到匹配的资源”,然后将其视为 authorizeOwnership() 中的错误?我的第一次尝试拒绝了 confirmOwnership() 中的 promise 当没有匹配的资源时,但这使事情变得更加复杂,因为很难区分这种情况(403 情况)和实际错误(500 情况)。
  • 最佳答案

    Is it OK for the promise returned by authorizeOwnership() to never be resolved in error scenarios? Will it cause a delay or a memory leak?



    是的,不解决 Bluebird promise 是安全的(公平地说,我检查过的任何其他实现 - pretty pictures here)。它本身没有全局状态。

    这是否是良好实践的问题是不同的。这就像一个同步 break某种意义上。就个人而言,我不是粉丝。

    Is it logically sound to resolve confirmOwnership() with null to say "no matching resource found" and then treat that as an error in authorizeOwnership()?



    这取决于您的 API。又是一个意见。它有效,但如果情况异常,我可能不会返回 null 而是指示失败。您可以使用错误对象区分拒绝。您可以用 AuthorizationError 拒绝例如,您创建的对象。注意 Bluebird 还支持类型化捕获。

    就像是:
    // probably shouldn't send the response to authorizeOwnership but use it externally
    // to be fair, should probably not take req either, but rid and userid
    var authorizeOwnership = Promise.method(function(req) {
        var rid      = Number(req.params.rid),
            userId   = Number(req.authInfo.userid;
            return confirmOwnership(rid, userId); // return the promise
        });
    });
    
    function ServerError(code,reason){
        this.name = "ServerError";
        this.message = reason;
        this.code = code;
        Error.captureStackTrace(this); // capture stack
    }
    var confirmOwnership = Promise.method(function(resourceId, userId) {
        // SequelizeJS... returns a bluebird promise
        return Resource.find({
            where: {id: resourceId, userId: userId}
        })
        .then(function(resource) {
            if(!resource) {
                throw new ServerError(403,"User not owner"); // promises are throw safe
            }
            return resource;
        });
    });
    

    接下来,在您的服务器中,您可以执行以下操作:
    app.post("/foo",function(req,res){
         authorizeOwnership(req).then(function(){
              res.send(200, "Owner Yay!");
         }).catch(ServerError,function(e){
                if(e.code === 403) return res.send(403,e.message);
                return res.send(500,"Internal Server Error");
         });
    });
    

    注意:您还在代码中使用了延迟反模式。没有必要做new Promise(function(...){在您的代码中,您可以简单地返回 promise 。

    关于promise - 不解决或拒绝 promise 是否安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23037183/

    相关文章:

    jquery - 尝试用 .then、.fail 和 .reject 打破 jQuery promise 链

    javascript - 如何让 Promise 对象成功函数中的代码在调用之后的代码之前执行?

    javascript - 从 Parse promise 链返回数据

    javascript - 定时 promise 队列/节流

    javascript - 使用 bluebird Promise 时,then() 没有被调用

    node.js - Babel 将异步到模块方法转换为带有 ES6 映射的 Bluebird

    javascript - 等待循环内的 promise

    javascript - 如何使用 Bluebird 将原始数据与 Promise.map 的响应一起传递?

    javascript - 打破 Catch block 内的异步函数

    javascript - promise 并批量更新到数据库