嗨,我正在尝试将我的功能与转换callback同步到promise
我想通过forEach循环添加到所有帖子 post.authorName 字段,并查询用户集合。
首先我尝试使用回调,但这是async,我需要一个sync工具
所以我使用promise,但我的结果仍然像回调
这是我的代码:
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 :(得分: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();
});
很明显,resolve
与getPostAuthorName
“同步”被称为“.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]