2017-08-11 8 views
0

こんにちは私の関数をからに変換しようとしています。
すべての投稿に追加したいと思っています。post.authorNameフィールドを経由してforEachループにアクセスし、にユーザリストを照会してください。
最初に私はコールバックを試みましたが、これはであり、ツールが必要です。
私はを使用しますが、依然として私の結果はコールバックのようです。
これは私のコードです:node.jsの約束と機能を同期させる方法

var mongo = require('mongodb').MongoClient(); 
var url = "mongodb://localhost:27017/blog"; 
var ObjectId = require('mongodb').ObjectID; 

var listPosts = function(req, res) { 
    find('post', {}, 10, {author: 1}) 
     .then(function(posts) { 

      var myPosts = posts; 

      const promises = []; 

      myPosts.forEach(function(post) { 

       console.log("hi i'm forEach" + '\n'); 
       console.log(post); 
       console.log('\n'); 

       const promise = new Promise(function(resolve, reject){ 
        getPostAuthorName(post.authorID) 
         .then(function(postAuthor){ 
          post.authorName = postAuthor; 
         }) 
         resolve(); 
       }); 

       console.log("i'm end of forEach and this is result:"); 
       console.log(post); 
       console.log('\n'); 

       promises.push(promise); 
      }); 

      Promise.all(promises).then(() => { 

       console.log('i should print at end' + '\n'); 

      }); 
     }); 
} 

var getPostAuthorName = function(authorID) { 
    return new Promise(function(resolve, reject){ 
     findOne('user', {_id: new ObjectId(authorID)}) 
      .then(function(result){ 

       console.log("i'm getPostAuthorName" + '\n'); 

       resolve(result.name); 
      }) 
    }) 
} 

var find = function(collection, cond = {}, limit = 0, sort = {}) { 
    return new Promise(function(resolve, reject){ 
     mongo.connect(url) 
      .then(function(db){ 
       db.collection(collection) 
        .find(cond).limit(limit).sort(sort).toArray() 
         .then(function(result){ 
          resolve(result); 
         }) 
      }) 
    }); 
} 

var findOne = function(collection, cond = {}){ 
    return new Promise(function(resolve, reject){ 
     mongo.connect(url) 
      .then(function(db){ 
       db.collection(collection).findOne(cond) 
        .then(function(result){ 

         console.log("i'm findOne" + '\n'); 

         resolve(result); 
        }) 
      }) 
    }) 
} 


listPosts(); 

と終了時に、私はこの結果を受け取る:

hi i'm forEach 

{ _id: 59888f418c107711043dfcd6, 
    title: 'FIRST', 
    content: 'this is my FIRST post', 
    timeCreated: 2017-08-07T16:03:13.552Z, 
    authorID: '5987365e6d1ecc1cd8744ad4' } 


i'm end of forEach and this is result: 
{ _id: 59888f418c107711043dfcd6, 
    title: 'FIRST', 
    content: 'this is my FIRST post', 
    timeCreated: 2017-08-07T16:03:13.552Z, 
    authorID: '5987365e6d1ecc1cd8744ad4' } 


hi i'm forEach 

{ _id: 598d60d7e2014a5c9830e353, 
    title: 'SECOND', 
    content: 'this is my SECOND post', 
    timeCreated: 2017-08-07T16:03:13.552Z, 
    authorID: '5987365e6d1ecc1cd8744ad4' } 


i'm end of forEach and this is result: 
{ _id: 598d60d7e2014a5c9830e353, 
    title: 'SECOND', 
    content: 'this is my SECOND post', 
    timeCreated: 2017-08-07T16:03:13.552Z, 
    authorID: '5987365e6d1ecc1cd8744ad4' } 


i should print at end 

i'm findOne 

i'm getPostAuthorName 

i'm findOne 

i'm getPostAuthorName 

関数は同期的に実行しない理由を。 解決策は何ですか?

+0

あなたが特定の質問への問題を軽減し、[MCVE]を提供していただけますか? – PeterMader

+0

あなたはただ1つの質問に答えることができます:**約束**は同期のプログラミングを保証しますか? –

+0

いいえ、もちろんです。プロミスは、非同期に対処するより良い方法です。非同期タスクを同期させないでください。 – PeterMader

答えて

1

約束事を作成しないでください!代わりに、チェーンの約束に能力を活用する:new Promiseコンストラクタを使用して、不要な約束を作成

var mongo = require('mongodb').MongoClient(); 
var url = "mongodb://localhost:27017/blog"; 
var ObjectId = require('mongodb').ObjectID; 

var listPosts = function() { 
    return find('post', {}, 10, {author: 1}) 
    .then(function (posts) { 
     var promises = posts.map(post => getPostAuthorName(post.authorID)); 
     return Promise.all(promises).then(names => names.map((name, index) => { 
     var post = posts[index]; 
     post.authorName = name; 
     return post; 
     }); 
    }); 
}; 

var getPostAuthorName = function(authorID) { 
    return findOne('user', {_id: new ObjectId(authorID)}).then(author => author.name); 
} 

var find = function(collection, cond = {}, limit = 0, sort = {}) { 
    return mongo.connect(url) 
    .then(db => db.collection(db) 
     .find(cond) 
     .limit(limit) 
     .sort(sort) 
     .toArray() 
    ); 
}; 

var findOne = function(collection, cond = {}) { 
    return mongo.connect(url).then(db => db.collection(db).findOne(cond)); 
}; 


listPosts().then(posts => console.log('Post:', post, ', author: ', post.authorName)); 

explicit-construction anti-patternと呼ばれています。

しかし、それはあなたのコード内で唯一の問題ではありませんでした。次のスニペットでは、不要な約束であなたは著者名の前に約束を解決が見つかったことを実現しなかったことを、コードは非常に複雑になる:

const promise = new Promise(function(resolve, reject){ 
    getPostAuthorName(post.authorID) 
    .then(function(postAuthor){ 
     post.authorName = postAuthor; 
    }) 
    resolve(); // why resolve immediately? 
}); 

代わりに、それはこのようになっている必要があります。

const promise = getPostAuthorName(post.authorID) 
    .then(function(postAuthor){ 
    post.authorName = postAuthor; 
    }); 
+0

tnx、これは正しく動作しています!驚くばかり。 –

1

お約束するコールバックを変換したい場合は、単にそのようなものにすることができます。今すぐ

function functionWithCallback(params, callback) 
{ 
    [...] 
    callback(true); 
} 

function functionWithPromise(params) 
{ 
    return new Promise((resolve, reject) => { 
     functionWithCallback(params, (done) => { 
      if (done) 
       return resolve(true); 
      reject(false); 
     }); 
    }); 
} 

を、あなたはあなたの関数を置くことを忘れないでください(awaitキーワードとの約束を同期させることができ非同期)。例:

あなたの問題は

const promise = new Promise(function(resolve, reject){ 
    getPostAuthorName(post.authorID) 
     .then(function(postAuthor){ 
      post.authorName = postAuthor; 
     }) 
     resolve(); 
}); 

が正しくだから、resolveが関連して "同期" と呼ばれていることは明らかです

const promise = new Promise(function(resolve, reject){ 
    getPostAuthorName(post.authorID) 
     .then(function(postAuthor){ 
      post.authorName = postAuthor; 
     }) 
    resolve(); 
}); 

ように見えるインデントこの(悪いインデント)コードである
async function main() 
{ 
    const p1 = functionWithPromise('1'); 
    const p2 = functionWithPromise('2'); 

    await p1; 
    await p2; 
    console.log('End'); 
} 
0

getPostAuthorNameに - .thengetPostAuthorName(これは非同期に呼び出されます)が呼び出される可能性があります。あなたは、あなたのコードは、あなたのコード内で「約束のコンストラクタアンチパターンを」アドレッシング

期待通りに振る舞うべき今

const promise = new Promise(function(resolve, reject){ 
    getPostAuthorName(post.authorID) 
     .then(function(postAuthor){ 
      post.authorName = postAuthor; 
      resolve(); 
     }) 
}); 

を移動する場合配列はすべて、

ので、あまりにも早く解決されます - そのうち上記は

を行う必要はありません、 getPostAuthorName以来

は約束を返す例です。

これは、すべてのこれらのアンチパターンを除去し、したがって

const promise = getPostAuthorName(post.authorID).then(function(postAuthor){ 
    post.authorName = postAuthor; 
    return; // returns "undefined", just like your resolve() results in 
}); 

に相当し、その代わりにプッシュ

でアレイを構築するが

ようなコードをもたらす

Promise.all(posts.map(

を使用して

const mongo = require('mongodb').MongoClient(); 
const url = "mongodb://localhost:27017/blog"; 
const ObjectId = require('mongodb').ObjectID; 

const listPosts = function(req, res) { 
    find('post', {}, 10, {author: 1}) 
    .then(posts => 
     Promise.all(posts.map(post => 
      getPostAuthorName(post.authorID) 
      .then(postAuthor => post.authorName = postAuthor) 
     )) 
    ) 
    .then(() => console.log('i should print at end' + '\n')); 
} 

const getPostAuthorName = authorID => 
    findOne('user', {_id: new ObjectId(authorID)}) 
    .then(result => result.name); 


const find = (collection, cond = {}, limit = 0, sort = {}) => 
    mongo.connect(url) 
    .then(db => 
     db.collection(collection) 
     .find(cond) 
     .limit(limit) 
     .sort(sort) 
     .toArray() 
    ); 

const findOne = (collection, cond = {}) => 
    mongo.connect(url) 
    .then(db => 
     db.collection(collection) 
     .findOne(cond) 
    ); 

私は再び罠に落ちたと思う..私はpostsを賭けはjavacript配列ではありません - その場合には、私は

const makeArray = collection => { 
    const ret = []; 
    collection.forEach(item => ret.push(item)); 
    return ret; 
}; 

のような機能になるだろうとの

 Promise.all(posts.map(post => 

を変更します

 Promise.all(makeArray(posts).map(post => 
関連する問題