Node.js return 多个异步让步同步的结果
Node.js return result of multiple asynchronous yield synchronously
我在 node.js 中使用 rethinkDB。以下请求工作正常:
function myFn () {
return co(function *() {
let query;
query = yield r.db("my-db")
.table("app")
.filter(r.row("id").eq(id))
.run(conn);
return query.toArray();
});
}
我想 return 多个 yield
异步的结果,但是以下失败了:
function myFn () {
return co(function *() {
let query, query2;
query = r.db("my-db")
.table("app")
.filter(r.row("id").eq(id))
.run(conn);
query2 = r.db("my-db")
.table("app")
.filter(...)
.run(conn);
return yield {q1 : query, q2 : query2};
});
}
然后我必须在每个元素上调用 toArray()
,所以在调用函数上我会这样做:
// using ramda.js
var res = R.map((el) => {
return el.toArray();
}, yield myFn);
但是我得到:
{
"q1": {
"isFulfilled": false,
"isRejected": false
},
"q2": {
"isFulfilled": false,
"isRejected": false
}
}
也有些奇怪:
// this works perfectly
return q.toArray();
// this returns the following :
return {q: q.toArray()};
"q": {
"isFulfilled": true,
"isRejected": false,
"fulfillmentValue": [ ... ]
}
我怀疑我遗漏了一些有关 yield
工作方式的信息,那么我怎样才能 return 多个 yield
结果的实现结果?
yield
不适用于包含承诺的对象 - 它仅适用于承诺本身。而不是 return yield {q1: query, q2: query2};
你必须做
return {q1: yield query, q2: yield query2};
但是,这有点问题,因为在 query
完成之前不会抛出 query2
中的错误。所以如果你不 just want to sequentially execute them,你将不得不使用 Promise.all
来等待一组承诺 "in parallel":
var [q1, q2] = yield Promise.all([query, query2]);
return {q1, q2};
(根据您使用的 promise 库,可能还有一个辅助函数将对象视为集合,而不仅仅是数组)
所以我在 reThinkDB google groups
上问了同样的问题:
引用 Ryan Paul 的话:
Your original attempt was actually really close, there were just two
things that you need to add:
- You need to yield the queries individually
- And you need to convert to array in the query if you don’t want to get cursors
Here’s a working example with the coroutine and yield:
function myFn() {
return co(function*() {
var conn = yield r.connect();
var query1 = yield r.db("test").table("fellowship")
.filter({species: "hobbit"})
.coerceTo("array").run(conn);
var query2 = yield r.db("test").table("fellowship")
.filter({species: "human"})
.coerceTo("array").run(conn);
conn.close();
return {q1: query1, q2: query2};
});
}
It’s also pretty simple to do without the coroutines and yield, and as
long as you use a promise library like bluebird. Here’s how I would do
it:
function myFn1() {
return r.connect().then(conn => {
return bluebird.all([
r.db("test").table("fellowship")
.filter({species: "hobbit"})
.coerceTo("array").run(conn),
r.db("test").table("fellowship")
.filter({species: "human"})
.coerceTo("array").run(conn)
]).then(items => ({q1: items[0], q2: items[1]}));
});
}
我在 node.js 中使用 rethinkDB。以下请求工作正常:
function myFn () {
return co(function *() {
let query;
query = yield r.db("my-db")
.table("app")
.filter(r.row("id").eq(id))
.run(conn);
return query.toArray();
});
}
我想 return 多个 yield
异步的结果,但是以下失败了:
function myFn () {
return co(function *() {
let query, query2;
query = r.db("my-db")
.table("app")
.filter(r.row("id").eq(id))
.run(conn);
query2 = r.db("my-db")
.table("app")
.filter(...)
.run(conn);
return yield {q1 : query, q2 : query2};
});
}
然后我必须在每个元素上调用 toArray()
,所以在调用函数上我会这样做:
// using ramda.js
var res = R.map((el) => {
return el.toArray();
}, yield myFn);
但是我得到:
{
"q1": {
"isFulfilled": false,
"isRejected": false
},
"q2": {
"isFulfilled": false,
"isRejected": false
}
}
也有些奇怪:
// this works perfectly
return q.toArray();
// this returns the following :
return {q: q.toArray()};
"q": {
"isFulfilled": true,
"isRejected": false,
"fulfillmentValue": [ ... ]
}
我怀疑我遗漏了一些有关 yield
工作方式的信息,那么我怎样才能 return 多个 yield
结果的实现结果?
yield
不适用于包含承诺的对象 - 它仅适用于承诺本身。而不是 return yield {q1: query, q2: query2};
你必须做
return {q1: yield query, q2: yield query2};
但是,这有点问题,因为在 query
完成之前不会抛出 query2
中的错误。所以如果你不 just want to sequentially execute them,你将不得不使用 Promise.all
来等待一组承诺 "in parallel":
var [q1, q2] = yield Promise.all([query, query2]);
return {q1, q2};
(根据您使用的 promise 库,可能还有一个辅助函数将对象视为集合,而不仅仅是数组)
所以我在 reThinkDB google groups
上问了同样的问题:
引用 Ryan Paul 的话:
Your original attempt was actually really close, there were just two things that you need to add:
- You need to yield the queries individually
- And you need to convert to array in the query if you don’t want to get cursors
Here’s a working example with the coroutine and yield:
function myFn() { return co(function*() { var conn = yield r.connect(); var query1 = yield r.db("test").table("fellowship") .filter({species: "hobbit"}) .coerceTo("array").run(conn); var query2 = yield r.db("test").table("fellowship") .filter({species: "human"}) .coerceTo("array").run(conn); conn.close(); return {q1: query1, q2: query2}; }); }
It’s also pretty simple to do without the coroutines and yield, and as long as you use a promise library like bluebird. Here’s how I would do it:
function myFn1() { return r.connect().then(conn => { return bluebird.all([ r.db("test").table("fellowship") .filter({species: "hobbit"}) .coerceTo("array").run(conn), r.db("test").table("fellowship") .filter({species: "human"}) .coerceTo("array").run(conn) ]).then(items => ({q1: items[0], q2: items[1]})); }); }