Callback 如何在node.js中将函数与承诺同步

Callback 如何在node.js中将函数与承诺同步,callback,promise,async,sync,javascript,node.js,asynchronous,synchronization,Callback,Promise,Async,Sync,Javascript,Node.js,Asynchronous,Synchronization,您好,我正在尝试将我的函数与convert to同步。 我想通过forEach循环向所有帖子添加post.authorName字段,并向用户集合查询 首先,我尝试了回调,但这是一个问题,我需要一个工具。 所以我使用了,但我的结果仍然像回调一样。 这是我的代码: var mongo = require('mongodb').MongoClient(); var url = "mongodb://localhost:27017/blog"; var ObjectId = require('mongo

您好,我正在尝试将我的函数与convert to同步。
我想通过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
为什么函数不同步运行。
解决方案是什么?

如果您想将回调转换为承诺,您可以简单地进行如下操作:

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

function functionWithPromise(params)
{
    return new Promise((resolve, reject) => {
        functionWithCallback(params, (done) => {
            if (done)
                return resolve(true);
            reject(false);
        });
    });
}
现在,您可以将承诺与关键字同步(不要忘记将函数设置为异步)。例如:

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

    await p1;
    await p2;
    console.log('End');
}
您的问题在于此代码(缩进严重)

正确的缩进看起来像

const promise = new Promise(function(resolve, reject){
    getPostAuthorName(post.authorID)
        .then(function(postAuthor){
            post.authorName = postAuthor;
        })
    resolve(); 
});
因此很明显,
resolve
相对于
getPostAuthorName
被“同步”调用-但是在
之前。然后
getPostAuthorName
可能被调用(异步调用)-因此,
承诺的
数组解析得太早了

所以,如果你移动它

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(
而不是用push构建一个数组

会导致类似代码的错误

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
不是一个JavaScript数组——在这种情况下,我会创建一个如下的函数

改变

        Promise.all(posts.map(post => 


如果你不需要承诺,就不要做出承诺!相反,利用连锁承诺的能力:

var mongo=require('mongodb').MongoClient();
变量url=”mongodb://localhost:27017/blog";
var ObjectId=require('mongodb')。ObjectId;
var listPosts=函数(){
返回find('post',{},10,{作者:1})
.然后(职能(职位){
var promises=posts.map(post=>getPostAuthorName(post.authorID));
返回Promise.all(promises).then(names=>names.map((name,index)=>{
var post=posts[索引];
post.authorName=名称;
回程站;
});
});
};
var getPostAuthorName=函数(authorID){
返回findOne('user',{u id:newobjectid(authorID)});
}
var find=函数(集合,cond={},limit=0,sort={}){
返回mongo.connect(url)
.then(db=>db.collection(db)
.find(cond)
.限额
.sort(排序)
.toArray()
);
};
var findOne=函数(集合,cond={}){
返回mongo.connect(url).then(db=>db.collection(db.findOne)(cond));
};
然后(posts=>console.log('Post:',Post',author:',Post.authorName));
使用
新承诺
构造函数创建不必要的承诺称为

但这并不是代码中唯一的问题:以下代码段中的“不必要的承诺”使代码变得如此复杂,以至于您没有意识到在找到作者姓名之前就解决了承诺:

const promise=新承诺(函数(解析、拒绝){
getPostAuthorName(post.authorID)
.then(函数(后作者){
post.authorName=后作者;
})
resolve();//为什么要立即解析?
});
相反,它应该是这样的:

const promise=getPostAuthorName(post.authorID)
.then(函数(后作者){
post.authorName=后作者;
});

能否请您将问题简化为一个特定的问题并提供一个答案?您只能回答一个问题:promise是否保证同步编程?不,当然不是。promise只是处理异步的更好方法。您不应该尝试使异步任务同步。避免promise构造函数反模式-
GetPostOuthorName
返回一个承诺,无需将调用包装为承诺…反过来,
findOne
mongo.connect
也会返回承诺,因此,也无需将它们包装在承诺构造函数中
承诺保证同步编程吗
-相反,承诺保证异步编程
const makeArray = collection => {
    const ret = [];
    collection.forEach(item => ret.push(item));
    return ret;
};
        Promise.all(posts.map(post => 
        Promise.all(makeArray(posts).map(post =>