2017-08-11 85 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

你只能回答一个问题:确保**保证同步编程吗? –

+0

不,当然不是。承诺是处理异步的更好方法。您不应该尝试使异步任务同步。 – PeterMader

回答

1

如果您不需要它们,请勿创建承诺!相反,利用的能力链的承诺:

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)); 

使用new Promise构造函数创建不必要的承诺,被称为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关键字(不要忘了承诺,把你的功能async)。例如:

async function main() 
{ 
    const p1 = functionWithPromise('1'); 
    const p2 = functionWithPromise('2'); 

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

您的问题是这个(不好缩进)代码

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

适当的缩进,它看起来像

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

所以很显然,resolve被称为 “同步” 相对于到getPostAuthorName - 但在getPostAuthorName(这是异步调用).then之前可能被称为 - 因此为什么你的promises阵列中所有已解决为时尚早

所以,如果你将它

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

现在,你的代码应该表现为你所期望

解决“的承诺构造反模式”在您的代码 - 它的上面是一个例子

由于getPostAuthorName返回一个承诺,有没有必要做

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

这相当于

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 =>