Node.js return result of multiple asynchronous yield synchronously

I am using rethinkDB with node.js. The following request works fine :

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

I would like to return the result of multiple yield asynchronously, however the following fails :

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

Then I have to call toArray() on each element, so on the calling function I do :

 // using ramda.js
  var res = R.map((el) => {
            return el.toArray();
        }, yield myFn);

However I get :

{
  "q1": {
    "isFulfilled": false,
    "isRejected": false
  },
  "q2": {
    "isFulfilled": false,
    "isRejected": false
  }
}

Something odd too :

 // this works perfectly
 return q.toArray();

 // this returns the following :
 return {q: q.toArray()};
 "q": {
   "isFulfilled": true,
   "isRejected": false,
   "fulfillmentValue": [  ...  ]
  }

I suspect I am missing something about the way yield works, so how can I return the fulfilled result of multiple yield results ?

Answers


yield doesn't work with objects that contain promises - it only works with promises itself. Instead of return yield {q1: query, q2: query2}; you'd have to do

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

However, that is kinda problematic as errors in query2 will not be thrown until query is done. So if you don't just want to sequentially execute them, you will have to use Promise.all to await a collection of promises "in parallel":

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

(Depending on the promise lib you're using, there might also be a helper function to treat objects as collections, not only arrays)


So I asked the same question on the reThinkDB google groups :

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

Need Your Help

String copy using pipes

c linux pipe fork dup

i have written the following code to copy a string "hello world" to another char array using fork and pipes instead of using standard library functions or standard i/o streams. The program is compi...

SQL WHERE Query brings back wrong values

sql

I have a stored procedure that is bringing back a list of results from our database. All of the select query is working apart from the last WHERE line. Even though the @ACTIVE variable is set to tr...