Promise.then函数内部没有改变外部变量

时间:2015-10-18 11:12:52

标签: javascript node.js promise thinky

在使用thinky.js的节点上,我试图遍历循环并将每个项目添加到数组中。然而,由于某种原因,这是行不通的。

在另一个地方,只是没有Promise.then功能,这是一种简洁而有效的工作。为什么这不起作用?

var fixedItems = [];
for (i in tradeItems) {
  var item = tradeItems[i];
  Item.get(item["id"]).run().then(function(result) {
    var f = { "assetid": result["asset_id"] };
    console.log(f);  // WOrks
    fixedItems.push(f); // Doesn't work
  });
}

console.log(fixedItems); // Nothing

2 个答案:

答案 0 :(得分:2)

承诺代表任务的未来结果。在这种情况下,您需要在任务(对fixedItems的调用)完成之前重新记录Item.get。换句话说,then函数还没有运行,所以没有任何内容被放入fixedItems

如果您希望在包含所有项目后使用fixedItems,则需要等待所有承诺解决。

你如何做到这一点取决于你正在使用的Promise库。此示例使用Promise.all,适用于许多库,包括本机ES6 Promises:

// Get an array of Promises, one per item to fetch.
// The Item.get calls start running in parallel immediately.
var promises = Object.keys(tradeItems).map(function(key) {
  var tradeItem = tradeItems[key];
  return Item.get(tradeItem.id);
});

// Wait for all of the promises to resolve. When they do,
//  work on all of the resolved values together.
Promise.all(promises)
  .then(function(results) {
    // At this point all of your promises have resolved.
    // results is an array of all of the resolved values.

    // Create your fixed items and return to make them available
    //  to future Promises in this chain
    return results.map(function(result) {
      return { assetid: result.asset_id }
    });
  })
  .then(function(fixedItems) {
    // In this example, all we want to do is log them
    console.log(fixedItems);
  });

推荐阅读:https://stackoverflow.com/a/28167340/560114

答案 1 :(得分:1)

您的问题是您在循环中的任何承诺执行完之前调用console.log(fixedItems)。另一种解决异步问题的更好方法是先将所有项ID放在一个数组中,然后检索单个查询中的所有项,这在数据库端也更有效。

var itemIds = tradeItems.map(function(item) {
    return item.id;
});

var fixedItems = [];

//you would need to write your own getItemsById() function or put the code
//to get the items here
getItemsById(itemIds).then(function(items) {

    items.forEach(function(item) {
        var f = { "assetid": result["asset_id"] };
        fixedItems.push(f);
    });

    whenDone();
});

function whenDone() {
    //you should be able to access fixedItems here
}

我无法通过thinky在单个查询中轻松找到如何通过ID查找多条记录,但我确实找到了可能有用的页面: http://c2journal.com/2013/01/17/rethinkdb-filtering-for-multiple-ids/

虽然这是我解决此问题的首选方法,但在继续使用后续代码之前,还可以使用多个查询并使用promise链等待所有问题得到解决。如果您想要走这条路线,请查看以下链接:http://promise-nuggets.github.io/articles/11-doing-things-in-parallel.html。 (注意:我还没有亲自使用Bluebird,但我认为该链接中的Bluebird示例可能已过时。map方法似乎是当前推荐的使用promises执行此操作的方法:{{ 3}}。)

更新:或者对于后一种选择,您只需使用上面joews的答案中的代码。