2016-06-13 96 views
1

我试图编写一个函数,直到函数内部的Promise解析完成才返回它的值。这是我想要做的一个简单的例子。如何等待直到承诺解决才返回值?

'use strict'; 

function get(db, id) { 
    let p = db.command('GET', 'group:${id}'); 
    p.then(g => { 
     g.memberNames = []; 
     g.members.forEach(id => { 
      User.get(db, id) 
       .then(profile => g.memberNames.push(profile.name)) 
       .catch(err => reject(err)); 
     }); 
     return g; 
    }); 
} 

这是一个函数,它请求一个组ID并返回该组的数据。一路上,它也将用户的姓名放入数据结构中以显示他们的姓名,而不是他们的用户ID。我的问题是,这是异步运行,并会跳过.then回调。当它返回g时,没有任何回调被调用,并且g.memberNames仍然是空的。有没有办法让函数等待返回g直到所有的回调被调用?

我见过很多关于等待的东西。这里有必要吗?将其他库添加到我的项目是非常不希望的。

+0

我认为要做到这一点的首选方法是将回调传递给你的函数,这将被称为准备时。 –

+0

放弃同步返回值的想法会更好。您的数据库API暴露了承诺,因此请使用它们,并且不要尝试将其变为同步。你可以写任何你想坚持异步/承诺模式的东西。这是改变你的观点的问题。 – trincot

回答

2

由于您的操作返回所有的配置文件名称也是异步你应该返回时,所有其他的异步操作完成一个承诺达成(或拒绝时,其中一个被拒绝)与Promise.all

function get(db, id) { 
    let p = db.command('GET', 'group:${id}'); 
    return p.then(g => { 
    return Promise.all(g.members.map(id => { 
     // NOTE: id is shadowing the outer function id parameter 
     return User.get(db, id).then(profile => profile.name) 
    }) 
    }) 
} 
+0

这正是我想要的。谢谢。 – rangeme

0
完成

有没有办法使函数等到返回g直到所有回调被调用?

是的,有。但是你应该改变你的思路,从“等到所有的回调被称为”改为“等到所有的承诺都满足”。事实上,Promise.all函数平凡地做到了这一点 - 它需要一个promise数组并返回一个新的promise,该promise使用一组结果来解析。

在你的情况,这将是

function get(db, id) { 
    return db.command('GET', 'group:${id}').then(g => { 
     var promises = g.members.map(id => { 
//        ^^^ never use `forEach` 
      return User.get(db, id).then(profile => profile.name); 
//   ^^^^^^ a promise for the name of that profile 
     }); 
     // 
     return Promise.all(promises).then(names => { 
//         ^^^^^^^^^^ fulfills with an array of the names 
      g.memberNames = names; 
      return g; 
     }); 
    }); 
}