【问题标题】:Async Patterns with Node.js and MongooseNode.js 和 Mongoose 的异步模式
【发布时间】:2014-05-13 02:23:35
【问题描述】:

具体来说,我正在使用 Mongoose 和 Node,但我想这是一个关于异步编码的更具概念性的问题。

我在 Mongoose 文档中看到了这个例子:

product.sold = Date.now();
product.save(function (err, product, numberAffected) {
  if (err) ..
})

但是,如果

product.save(...) 

执行速度比

product.sold = Date.now()

你不会在更新之前保存...吗? 也许我在这里遗漏了一些东西(在概念层面)?是什么让这段代码在异步环境中“安全”。

更具体地说,我使用 doc.addToSet 作为“更新”步骤,如果它有一个回调我会感觉好多了我可以嵌入 doc.save 介入(以确保异步行为)。想法?

附言。我不只是使用 model.update 因为我需要验证。

【问题讨论】:

    标签: javascript node.js mongodb asynchronous mongoose


    【解决方案1】:

    异步并不意味着每行都同时执行。在这种情况下 product.sold 被分配并像正常操作一样完成,然后 save 被依次调用。

    异步部分发生在 product.save 中。发生的事情是您将一个函数作为参数传递给 product.save ,它也是一个函数。这称为匿名回调。它没有名称,并从 product.save 内部异步调用。

    执行顺序如下:

    1. Date.now() 被分配给 product.sold 并且操作完成
    2. product.save(callback(...){...}) 被调用
    3. product.save 到达回调并执行它,即 product.save 的定义中有一行写着callback.call(...),然后 product.save 返回
    4. 在 product.save 之后(您尚未列出)但在回调完成之前继续执行下一行
    5. 回调在某个时候完成

    所以您更新产品并成功保存。您传递的匿名函数并不是实际保存它的东西,而是一个异步扩展来做您想做的事情,即处理错误或确保保存正确数量的项目。

    【讨论】:

    • 感谢您的回复。那么,是否可以因为“更新”(product.sold)只是一个分配,而不是一个函数?如果“更新”是一项耗时的功能,您是否会面临在(product.sold)完成之前运行“保存”(product.save)的危险?在我的特定用例中,“更新”实际上是一个函数 doc.addToSet。
    • 我认为问题不在于该功能是否耗时。您需要考虑的是函数的 方式 行为方式,即它是否在执行 all 后返回?还是返回之前做所有事情并依靠处理程序(或回调)来处理所有函数代码的结果?
    • 例如,假设您在一家餐馆点菜。最后,您希望得到您点的东西,但每个餐厅的准备方式可能会有所不同。所以,让我们假设在restaurant_Foo,有人接了你的订单,然后去厨房,准备好食物,然后把它带给你,下另一个订单;这是同步行为(如product.sold = Date.now())。但是,如果相反,在restaurant_Boo 中,所有订单都被接受,然后人们等待食物准备好(就像在大多数餐馆一样),这可以称为 异步
    【解决方案2】:

    您不必担心更新操作会在保存之前发生,因为它是阻塞的。

    要了解阻塞(同步)和非阻塞(异步)操作之间的区别,请使用以下基本异步代码:

    function async(callback) {
      process.nextTick(callback);
    }
    
    async(function() {
      console.log('foo');
    }
    console.log('bar');
    

    这将按顺序显示bar,然后是foo。这里的关键是函数process.nextTick(cb),它会延迟回调的执行。

    由于 NodeJS 只使用一个线程,它会等待整个函数栈返回,然后在进程的下一个循环中执行回调。现在,如果您的更新操作是异步的,则您必须在传递给该操作的回调函数中执行保存操作。

    但是,由于不是(您可以从文档中看到,而且通常,该函数不接受任何回调参数这一事实是一个很好的指示),该函数的执行将被阻塞,直到该更新操作返回。

    【讨论】:

    • 这是有道理的。所以,我将阻塞事件循环,但这可能不是什么大问题,因为没有 I/O 正在进行。
    猜你喜欢
    • 2015-02-19
    • 1970-01-01
    • 2012-09-24
    • 2015-09-14
    • 2021-10-18
    • 1970-01-01
    • 2012-09-02
    • 2021-04-28
    • 2012-03-20
    相关资源
    最近更新 更多