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