2016-06-13 62 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; 
     }); 
    }); 
}