使用 Node.Js 和 Promises,你如何返回一个已经实现的 Promise? [复制]

Posted

技术标签:

【中文标题】使用 Node.Js 和 Promises,你如何返回一个已经实现的 Promise? [复制]【英文标题】:Using Node.Js and Promises, how do you return a fulfilled promise? [duplicate] 【发布时间】:2018-10-14 08:33:04 【问题描述】:

我正在使用 Mongoose,并且正在从数据库中查找客户。如果客户存在,我将返回一个 customerId。但是,如果客户不存在,我想创建它们,然后返回客户 ID。无论哪种情况,我都希望承诺以 customerID 结尾。无论如何,虽然我在文档中看到可以使用“Promise.resolve”立即包装返回值,但我收到了一个错误。当尝试通过包装它们的返回值来使同步任务与 Node 更加一致时,此功能显然很有用。无论如何,有什么更好的方法来处理这个或返回一个承诺?归根结底,我希望代码返回客户对象或陷入捕获/错误。

TypeError: Promise.resolve is not a constructor

下面是代码(我删掉了一些安全方面的东西,但我想我没有做任何严重的改动)。

Customer.findOne(email: email).then((customer) => 
    if (customer) 
        return  Promise.resolve(customer);
    
    else 
        return new Customer(email: email).save();
        
).then( function(customer) ...

这真的是关于 Promises,而不是 Mongoose 或 MongoDb。如果你处于一个处于 Promise 内部并且想要将值返回到链中的情况,你会怎么做?

【问题讨论】:

对于猫鼬 API,return Customer.findOneAndUpdate( email , , "upsert": true, "new": true )。除了"new": true 而不是"returnOriginal": false 之外,基本上与标准API 相同。当数据库已经这样做时,无需链接承诺。 太美了! 【参考方案1】:

这里不需要 Promise.resolve() 。如果then 处理程序返回非承诺,则then 调用返回的承诺将使用该值进行解析。换句话说,它已经被包裹了,所以再次包裹它是多余的。

另外,else 也是多余的,因为 return 语句退出当前正在执行的函数:

Customer.findOne(email: email).then((customer) => 
    if (customer) 
        return customer;
    
    return new Customer(email: email).save();    
).then( function(customer) ...

Promise.resolve()Promise.reject() 通常适用于没有实际异步操作发生的特殊情况的操作,但为了保持一致性,您仍然希望它们在这些情况下返回 Promise。

作为一个简单的例子,假设我有一堆具有uid 属性的对象,它们可能有也可能没有相应的username 属性。我想确保它们都具有username 属性,因此我编写了一个可以调用所有它们的函数,如果缺少用户名,它将从数据库中查找用户名。为了保持一致性,我希望这个函数总是返回一个承诺,即使 username 已经存在并且实际上不需要查找。另外,我可以添加一个案例,如果 uid 丢失,promise 将拒绝而不会浪费时间尝试将 undefined 查找为 uid。

可能看起来像这样:

function ensureUsername(user) 
    if ('username' in user) return Promise.resolve(user);
    return lookUpUsernameByUid(user.uid)
        .then((username) => 
            user.username = username;
            return user;
        );

Promise.resolve() 在处理可能是也可能不是承诺的值时也非常有用。这是因为如果它已经是一个承诺,它只是简单地返回值。

假设你想编写一个函数foo 来调用一些回调函数。回调函数可能是异步的,也可能不是异步的——即它可能返回一个承诺,但不是必须的。你是如何做到这一点的?

这很简单。只需将回调的结果放在Promise.resolve 中并将then 链接到它上面:

function foo(cb) 
    return Promise.resolve(cb())
        .then((callbackResult) => 
            // Do whatever...
        );

无论cb 返回一个使用callbackResult 解析的promise 还是直接返回callbackResult,这都将起作用。

【讨论】:

我尝试了“Promise.resolve(cb())”并收到错误。我不知道 API 是否不同,但在我的 Node.js/Express 中这似乎无效。我在传统的 JS 中见过很多这种方法。 我不希望它适用于您的代码,因为您没有使用这样的回调。这只是一个通用示例,我将其作为Promise.resolve 用途的演示。我经常发现了解某物的用途更容易理解它的用途。 :)

以上是关于使用 Node.Js 和 Promises,你如何返回一个已经实现的 Promise? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何在Node.js中对使用promises和事件发射器的函数进行单元测试?

如何使用 node.js 和 Promises 将特定行的行添加到文件的内容

使用 Javascript(以及 Node.js)使用 async/await 和 Promises 的正确方法是啥 [重复]

Node.js:何时使用 Promises 与 Callbacks

Node.js&co - 避免混合promises和事件回调

Node.js、Promises & Recursion - 可能吗?