【问题标题】:Lexical scoping in a for loop enclosing a promise?包含promise的for循环中的词法范围?
【发布时间】:2014-07-24 13:52:32
【问题描述】:

我有一个ids 对象,它将id 字符串映射到product 对象。

for id of ids
  product = ids[id]
  console.log product # Prints out something different each loop. :)
  Product.create(product).then ->
    console.log product # Only prints out the last id each loop. :(

我正在使用一个用于数据库交互的库,它公开了 Promise(由上面的 then 函数表示)。我试图在then 函数中打印出product 变量,但我似乎只在ids 中获得了最后一个id,所以看起来这是一个范围问题。如何正确确定 product 变量的范围,以便它在每个循环的 then 函数中打印出不同的产品?

【问题讨论】:

标签: javascript coffeescript scope promise lexical-scope


【解决方案1】:

@false 确实找到了right duplicate describing your issue。实际上,您遇到了一个范围界定问题,其中product 对于循环体来说是非本地的,并且您只能从异步回调中获取最后一项。

如何正确确定产品变量的范围,以便它在 then 回调中打印出不同的产品?

在惯用的coffeescript中,您将在循环中使用do notation作为IEFE:

for id of ids
  do (product = ids[id]) ->
    console.log product
    Product.create(product).then ->
      console.log product

或者,直接从of-loop 中提取属性值:

for id, product of ids
  do (product) ->
    …

【讨论】:

    【解决方案2】:

    Bergi 的代码会误导 IMO,因为它一次运行整个循环,而不是按顺序运行。出于这个原因,我只是将所有代码提升到 Promise 中,而不是混合使用同步和异步:

    Promise.resolve(product for _, product of ids).then next = (products) ->
      [product, products...] = products
      if product
        console.log product
        Product.create(product).then ->
          console.log product
          next products
    .then ->
      console.log "all done"
    

    区别在于:

    • 就像在真正的循环中一样,直到前一个项目完成后,下一个项目才会运行
    • 就像在真正的循环中一样,下一行(只需要在循环完全完成后运行then ->

    真正循环的这些属性比你可以在几天内学会的表面语法重要得多。

    让它运行并查看日志中的差异。

    【讨论】:

    • 我认为 OP 不想按顺序执行它们。您当然可以轻松地并行运行它们并通过Promise.map((p for _, p of ids), Product.create) 或类似的方式收集它们的结果。我的回答实际上不是关于承诺部分,而是关于关闭。
    • @Bergi 我认为他甚至没有意识到这种差异(顺序与并行),我是来开导的
    猜你喜欢
    • 1970-01-01
    • 2020-11-13
    • 2022-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 2013-07-15
    相关资源
    最近更新 更多