如何在node.js

时间:2017-08-11 08:11:37

标签: javascript node.js asynchronous promise synchronization

嗨,我正在尝试将我的功能与转换同步到 我想通过forEach循环添加到所有帖子 post.authorName 字段,并查询用户集合
首先我尝试使用回调,但这是,我需要一个工具 所以我使用,但我的结果仍然像回调 这是我的代码:

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

为什么函数不能同步运行。 什么是解决方案?

3 个答案:

答案 0 :(得分:3)

如果你不需要,不要创造承诺!相反,利用链接承诺的能力:

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构造函数创建不必要的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;  
  });

答案 1 :(得分:2)

如果您想将回调转换为承诺,您可以简单地制作类似的内容:

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关键字同步promises(不要忘记将函数 async )。示例:

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

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

答案 2 :(得分: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(); 
});

很明显,resolvegetPostAuthorName“同步”被称为“.then - 但在getPostAuthorName promises之前(被异步调用)可能会被调用 - 因此,为什么你的const promise = new Promise(function(resolve, reject){ getPostAuthorName(post.authorID) .then(function(postAuthor){ post.authorName = postAuthor; resolve(); }) }); 数组太早解决了

所以,如果你移动它

getPostAuthorName

现在,您的代码应该按预期行事

在你的代码中解决“promise构造函数反模式” - 以上是一个例子

由于const promise = new Promise(function(resolve, reject){ getPostAuthorName(post.authorID) .then(function(postAuthor){ post.authorName = postAuthor; resolve(); // resolves to "undefined" }) }); 返回Promise,因此无需执行

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

而不是使用push

构建数组

会产生类似

的代码
posts
  

我想我再次陷入陷阱..我敢打赌const makeArray = collection => { const ret = []; collection.forEach(item => ret.push(item)); return ret; }; 不是javacript数组 - 在这种情况下我会创建一个像

这样的函数
        Promise.all(posts.map(post => 

并更改

        Promise.all(makeArray(posts).map(post => 

RewriteEngine On
RewriteRule ^dir1/(.*)$ http://newdomain.com/$1 [R,L,NC]