Javascript 在Promise.then函数中未更改外部变量

Javascript 在Promise.then函数中未更改外部变量,javascript,node.js,promise,thinky,Javascript,Node.js,Promise,Thinky,在使用thinky.js的节点上,我试图迭代一个循环,并将每个项添加到一个数组中。然而,出于某种原因,这是行不通的 在另一个地方,它是一致的和有效的,只是没有承诺。为什么这不起作用 var fixedItems=[]; 适用于(贸易项目中的i){ var项目=贸易项目[i]; Item.get(Item[“id”]).run().then(函数(结果){ var f={“assetid”:结果[“资产id”]}; console.log(f);//有效 fixedItems.push(f);/

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

在另一个地方,它是一致的和有效的,只是没有承诺。为什么这不起作用

var fixedItems=[];
适用于(贸易项目中的i){
var项目=贸易项目[i];
Item.get(Item[“id”]).run().then(函数(结果){
var f={“assetid”:结果[“资产id”]};
console.log(f);//有效
fixedItems.push(f);//不起作用
});
}

console.log(fixedItems);//没有任何内容
您的问题是,在循环中的任何承诺完成执行之前,您正在调用
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查找多个记录,但我确实找到了这个页面,它可能会有所帮助:

虽然这是我解决这个问题的首选方法,但在继续执行后续代码之前,仍然可以使用多个查询并使用承诺链等待所有查询都得到解决。如果您想走这条路线,请查看以下链接:。(注意:我个人没有使用过Bluebird,但我认为该链接中的Bluebird示例可能已经过时。
map
方法似乎是当前推荐的实现承诺的方法:)

更新:或者对于后一个选项,您可以使用上面joews答案中的代码。

承诺代表任务的未来结果。在本例中,在任务(对
Item.get
的调用)完成之前,您正在记录
fixedItems
。换句话说,
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);
  });

推荐阅读:.

如果
项.get(项[“id”]).run()
是异步的,那么在另一个地方开始执行之前,您就记录了fixeditems,它是一致的和工作的-您能显示相同的工作代码吗?这是我回答的一个很好的替代方法。但是我不认为,
Promise.all()
并行执行承诺(我错了吗?),如果有一种方法可以并行执行而不是顺序执行,那么效率会更高。这是一个相当小的问题(可能是过早的优化),但我想知道是否有一种简单的方法可以用本机承诺并行执行。你错了,它们是并行运行的。事实上,当你调用Promise.all时,它们已经并行运行了。承诺总是代表一个正在运行的任务,所以如果你有一个承诺,它的任务正在进行中。事实上,带承诺的串行执行需要更多的努力。啊,我现在明白了(当然,
map
函数是同步运行的,所以承诺马上开始执行…)。如何使用
Promise.map
?你链接的文章没有提到这一点,但这在这里也适用,不是吗?(与
Promise.all
,没有什么特别的优势,我只是想提一下)。对于支持它的库,您也可以使用
Promise.map
。我选择了Promise.all,因为它是的一部分,它比许多像Bluebird和Q这样的库小得多。