【问题标题】:Node.js return result of multiple asynchronous yield synchronouslyNode.js同步返回多个异步yield的结果
【发布时间】:2016-02-22 18:23:20
【问题描述】:

我正在将 rethinkDB 与 node.js 一起使用。以下请求工作正常:

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

我想异步返回多个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 工作方式的某些内容,那么如何返回多个 yield 结果的已完成结果?

【问题讨论】:

  • 它究竟是如何失败的?您收到错误消息吗?您得到的结果是否与预期不同?
  • yield { q1: r.db(" "), q2: r.db(" ")};.
  • @nils 我更新了我的问题,谢谢。
  • @torazaburo 我不确定你的意思是什么?
  • 我的意思是,如果你返回一个对象,那么每个属性的值将被并行等待,当所有值都解决后,产量将“返回”,评估其属性值为的并行对象承诺的已解决值。换句话说,不要让出单个值,然后再让出一个让出的对象;相反,使用包含所有异步元素的单个对象产生一次。

标签: node.js promise ecmascript-6 yield rethinkdb


【解决方案1】:

yield 不适用于包含 Promise 的对象 - 它仅适用于 Promise 本身。而不是return yield {q1: query, q2: query2}; 你必须这样做

return {q1: yield query, q2: yield query2};

但是,这有点问题,因为在完成 query 之前不会抛出 query2 中的错误。因此,如果您不使用 just want to sequentially execute them,则必须使用 Promise.all 来“并行”等待一系列承诺:

var [q1, q2] = yield Promise.all([query, query2]);
return {q1, q2};

(根据您使用的 promise 库,可能还有一个辅助函数将对象视为集合,而不仅仅是数组)

【讨论】:

  • 第一种方法仍然返回{ "isFulfilled": false, "isRejected": false },而第二种方法 (Promise.all) 仍然返回 rethink Cursors ([ Cursor { _type: 3, _eachCb: [Function], _conn: TcpConnection { host: 'localhost', port: 28015, db: undefined, authKey: '', timeout: 20, ssl: false, outstandingCallbacks: [Object],....
  • 嗯,这看起来不像 run() 返回一个承诺。您是否应该更喜欢yield .toArray() 的结果?我对重新思考并不十分熟悉,但看起来游标不是可屈服或可屈服的。
  • run() 返回一个游标,我的理解是它可以像我的第一个示例一样与 yield 一起使用(也有 rethinkdb.com/blog/rethinkdbdash-iojs)。
  • 嗯,他们的示例只使用createinsert 之类的命令,其中run() 可能会直接返回一个promise(什么都没有?)。我假设 filter().run() 返回一个 Cursor 或一个 Cursor 的 Promise,然后 toArray() 返回一个数组的 Promise。您可以尝试改用yield.all([…])query.toArray()(yield query).toArray() 吗?
  • 我实际上不知道,不确定这是否有官方信息(我很新去重新思考)。
【解决方案2】:

所以我在reThinkDB google groups 上问了同样的问题:

引用瑞安·保罗的话:

您最初的尝试实际上非常接近,只有两个 您需要添加的内容:

  • 您需要单独生成查询
  • 如果您不想获取游标,则需要在查询中转换为数组

这是一个使用协程和 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};
  });
}

没有协程和 yield 也很简单,并且作为 只要你使用像 bluebird 这样的 promise 库。我会这样做 它:

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

【讨论】:

  • 好的,所以.coerceTo("array") 是我的答案中缺少的部分。感谢您的更新!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-30
  • 1970-01-01
  • 1970-01-01
  • 2014-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多