I started reading You Don't Know JS: Async and Performance and tripped at delegating recursion example: I went through the code mentally and got the right result, but can't comprehend the description of the intermediate steps in the book.
Tried inserting console.log() into the functions' body, tried debugger to examine the call stack and still cannot conform my mental model of the code to the one, that's in the book.
function run(), which gets generator function as parameter, creates its instance and run it to the end, passing each previously yielded value to the next() call.
function run(gen) {
var args = [].slice.call( arguments, 1), it;
// initialize the generator in the current context
it = gen.apply( this, args );
// return a promise for the generator completing
return Promise.resolve()
.then( function handleNext(value){
// run to the next yielded value
var next = it.next( value );
return (function handleResult(next){
// generator has completed running?
if (next.done) {
return next.value;
}
// otherwise keep going
else {
return Promise.resolve( next.value )
.then(
// resume the async loop on
// success, sending the resolved
// value back into the generator
handleNext,
// if `value` is a rejected
// promise, propagate error back
// into the generator for its own
// error handling
function handleErr(err) {
return Promise.resolve(
it.throw( err )
)
.then( handleResult );
}
);
}
})(next);
} );
}
the example code:
function *foo(val) {
if (val > 1) {
// generator recursion
val = yield *foo( val - 1 );
}
return yield request( "http://some.url/?v=" + val );
}
function *bar() {
var r1 = yield *foo( 3 );
console.log( r1 );
}
run( bar );
and for convenience's sake we can implement function request() like this:
function request(url) {
return new Promise(function(resolve){
setTimeout(function(){
resolve( url.match(/v=(\d+)$/)[1] );
},1000);
});
}
The book provides these steps:
run(bar) starts up the *bar() generator.
foo(3) creates an iterator for *foo(..) and passes 3 as its val parameter.
Because 3 > 1, foo(2) creates another iterator and passes in 2 as its val parameter.
Because 2 > 1, foo(1) creates yet another iterator and passes in 1 as its val parameter.
1 > 1 is false, so we next call request(..) with the 1 value, and get a promise back for that first Ajax call.
That promise is yielded out, which comes back to the *foo(2)
generator instance.
The yield * passes that promise back out to the *foo(3) generator
instance. Another yield * passes the promise out to the *bar()
generator instance. And yet again another yield * passes the promise
out to the run(..) utility, which will wait on that promise (for the
first Ajax request) to proceed.
When the promise resolves, its fulfillment message is sent to resume
*bar(), which passes through the yield * into the *foo(3) instance, which then passes through the yield * to the *foo(2) generator
instance, which then passes through the yield * to the normal yield
that's waiting in the *foo(3) generator instance.
That first call's Ajax response is now immediately returned from the
*foo(3) generator instance, which sends that value back as the result of the yield * expression in the *foo(2) instance, and
assigned to its local val variable.
Inside *foo(2), a second Ajax request is made with request(..),
whose promise is yielded back to the *foo(1) instance, and then
yield * propagates all the way out to run(..) (step 7 again). When
the promise resolves, the second Ajax response propagates all the
way back into the *foo(2) generator instance, and is assigned to
its local val variable.
Finally, the third Ajax request is made with request(..), its
promise goes out to run(..), and then its resolution value comes
all the way back, which is then returned so that it comes back to
the waiting yield * expression in *bar().
Everything is clear until the 8th step.
...which then passes through the yield * to the normal yield
that's waiting in the *foo(3) generator instance.
Why waiting in foo(3), not in foo(2)? I thought after Promise fulfillment, its value (1) is passed to return yield request( "http://some.url/?v=" + val ); line, in place of yield, so we have return 1 at the end of foo(1). And then 1 is passed to val = yield *foo( val - 1 ); line, again, in place of yield, so we have val = 1 inside foo(2) call. After that, a second request() is made and yields a Promise to foo(3).
Then foo(3) yields the Promise to bar(), then bar() yields the Promise to run(). run() waits on the second Promise, just as with the first promise, and so on.
JSFiddle
What have I overlooked?
What have I overlooked?
Nothing. In steps 8 and 9, the generator they should be referring to is the one created by foo(1), not by foo(3).
Related
How to check if there is already running function and if it is exist listen to this function result;
async function a() {
// wait 5 seconds and return foo = foo + 1;
// if A is already running await and return result of this running function A instead result;
}
If I translate the problem correctly, A returns a promise that is asynchronously settled. While the promise is pending, all calls to a wrapper function around A should return the currently pending promise.
If, however, A has not been called, or a previously return promise has been settled, A should be called again.
This can be achieved by chaining off the promise returned by A, using promise handlers to determine results are no longer pending, and have the wrapper function return the chained promise. This example code speeds up the process a little - four successive calls made to a 500ms apart get the same fulfilled value from A which is taking 2000ms to perform a mythical asynchronous task:
// promise a delay
const delay = ms => new Promise(resolve=>setTimeout(resolve, ms));
// async function A
let foo =0;
async function A() {
await delay( 2000); // 2 second example
return foo = foo + 1;
}
// Wrapper function a
const a=(()=>{
let pending = null;
const onfulfill = data => { pending = null; return data};
const onreject = err => { pending = null; throw err};
let a = ()=> pending || (pending = A().then(onfulfill, onreject));
return a;
})();
// and test
async function test() {
for( let i=1; i < 11; ++i) {
a().then( data=> console.log(`a() call ${i} fulfills with ${data}`));
await delay(500);
}
}
console.log(" a is a named function ", a.name == 'a')
test();
a is coded to be a named function which minimizes run time object creation by using the two parameter form of then and passing pre-compiled functions as handler arguments.
The catch handler re-throws the error for caller code to handle.
synchronous and asynchronous code don't mix well together. Calls to wrapper function a always receive a pending promise value in return.
Solution
You can create class that will be execute one flow (maximum) and await result if flow already running. It may looks something like that:
class OneThreadExecutor {
// Boolean variable which represents is task running right now
taskRunning = false;
// All Promise.resolve callbacks
listeners = [];
// Accept initial value
constructor(value = 0) {
this.value = value;
}
// Send [result = value + 1] after 5 sec
startNewTask = () => {
this.taskRunning = true;
setTimeout(() => {
this.taskRunning = false;
return this.sendResult();
}, 5000)
}
// Call all Promise.resolve callbacks, and pass [value + 1] to them
sendResult = () => {
for (const listener of this.listeners) {
listener(++this.value);
}
this.listeners = [];
}
// Main method that exec one task
getResult = () => new Promise(resolve => {
// Add callback to queue
this.listeners.push(resolve);
// Start new task if necessary
if (!this.taskRunning) this.startNewTask();
})
}
General concept
Async getResult method will register promise in class' queue. Any successfull task execution will send result to queue. Current task returns value + 1 on each getResult call and take 5 seconds for whole flow.
Usage
const a = new OneThreadExecutor(); // value = 0 by default
// will start task#1, 5 sec left till .then call, value = 1
a.getResult().then(...)
// 2.5 sec left, task#1 is already half progress, value = 2
setTimeout(() => {
a.getResult().then(...)
}, 2500)
Async/await
const a = new OneThreadExecutor(3); // let's set value = 3 initially
// will start task#1, 5 sec left till .then call, value = 4
a.getResult();
// wait till task#1 completed, 5 sec left, value = 5
const value = await a.getResult();
// will start task#2 bacause not task running, 5 sec left, value = 6
a.getResult();
Cons
In demo solution we already expect successful task execution, without error handling, so you may need to extend it for proper error catching during task execution.
var is_a_running = false;
function a() {
if (is_a_running == false) {
is_a_running = true
//do something
//after you have done the thing
is_a_running = false
}
else if (is_a_running == true){
result();
}
}
This is should help you
I have a function F that starts an asynchronous process X. The function returns a promise that is resolved when X ends (which I learn by means of a promise returned by X).
While the (w.l.o.g.) first instance of X, X1, is running, there may be more calls to F. Each of these will spawn a new instance of X, e.g. X2, X3, and so on.
Now, here's the difficulty: When X2 is created, depending on the state of X1, X1 should conclude or be aborted. X2 should start working only once X1 is not active any more. In any case, the unresolved promises returned from all previous calls to F should be resolved only once X2 has concluded, as well - or, any later instance of X, if F gets called again while X2 is running.
So far, the first call to F invokes $q.defer() to created a deferred whose promise is returned by all calls to F until the last X has concluded. (Then, the deferred should be resolved and the field holding it should be reset to null, waiting for the next cluster of calls to F.)
Now, my issue is waiting until all instances of X have finished. I know that I could use $q.all if I had the full list of X instances beforehand, but as I have to consider later calls to F, this is not a solution here. Ideally, I should probably then-chain something to the promise returned by X to resolve the deferred, and "unchain" that function as soon as I chain it to a later instance of X.
I imagine that something like this:
var currentDeferred = null;
function F() {
if (!currentDeferred) {
currentDeferred = $q.defer();
}
// if previous X then "unchain" its promise handler
X().then(function () {
var curDef = currentDeferred;
currentDeferred = null;
curDef.resolve();
});
return currentDeferred.promise;
}
However, I don't know how to perform that "unchaining", if that is even the right solution.
How do I go about this? Am I missing some common pattern or even built-in feature of promises, or am I on the wrong track altogether?
To add a little context: F is called to load data (asynchronously) and updating some visual output. F returns a promise that should only be resolved once the visual output is updated to a stable state again (i.e. with no more updates pending).
F is called to load data (asynchronously) and updating some visual output. F returns a promise that should only be resolved once the visual output is updated to a stable state again (i.e. with no more updates pending).
Since all callers of F will receive a promise they need to consume, but you only want to update the UI when all stacked calls have completed, the simplest thing is to have each promise resolve (or reject) with a value telling the caller not to update the UI if there's another "get more data" call pending; that way, only the caller whose promise resolves last will update the UI. You can do that by keeping track of outstanding calls:
let accumulator = [];
let outstanding = 0;
function F(val) {
++outstanding;
return getData(val)
.then(data => {
accumulator.push(data);
return --outstanding == 0 ? accumulator.slice() : null;
})
.catch(error => {
--outstanding;
throw error;
});
}
// Fake data load
function getData(val) {
return new Promise(resolve => {
setTimeout(resolve, Math.random() * 500, "data for " + val);
});
}
let accumulator = [];
let outstanding = 0;
function F(val) {
++outstanding;
return getData(val)
.then(data => {
accumulator.push(data);
return --outstanding == 0 ? accumulator.slice() : null;
})
.catch(error => {
--outstanding;
throw error;
});
}
// Resolution and rejection handlers for our test calls below
const resolved = data => {
console.log("chain done:", data ? ("update: " + data.join(", ")) : "don't update");
};
const rejected = error => { // This never gets called, we don't reject
console.error(error);
};
// A single call:
F("a").then(resolved).catch(rejected);
setTimeout(() => {
// One subsequent call
console.log("----");
F("b1").then(resolved).catch(rejected);
F("b2").then(resolved).catch(rejected);
}, 600);
setTimeout(() => {
// Two subsequent calls
console.log("----");
F("c1").then(resolved).catch(rejected);
F("c2").then(resolved).catch(rejected);
F("c3").then(resolved).catch(rejected);
}, 1200);
.as-console-wrapper {
max-height: 100% !important;
}
(That's with native promises; adjust as necessary for $q.)
To me, "don't update" is different from "failed," so I used a flag value (null) rather than a rejection to signal it. But of course, you can use rejection with a flag value as well, it's up to you. (And that would have the benefit of putting the conditional logic ["Is this a real error or just a "don't update"?] in your catch handler rather than your then [is this real data or not?]... Hmmm, I might go the other way now I think of it. But that's trivial change.)
Obviously accumulator in the above is just a crude placeholder for your real data structures (and it makes no attempt to keep the data received in the order it was requested).
I'm having the promise resolve with a copy of the data in the above (accumulator.slice()) but that may not be necessary in your case.
The documentation says that "You can also provide a parameter to the next method to send a value to the generator." Where does it sends it to?
For example, take these 3 generators:
function* one() {
while(true) {
var value = yield null;
}
}
var g1 = one(); g1.next();
g1.next(1000); //yields null
function* two() {
var i = 0;
while (true) {
i += yield i;
}
}
var g2 = two(); g2.next();
g2.next(1000) // yields 1000
function* three(){
var index = 0;
while (true)
yield index++;
}
g3 = three();
g3.next();
g3.next(1000); // yields 1
In generators 3 and 1, the argument passed has no effect on next. Why is that? How does generator 2 calculates its return value? Why it is affected by the given argument?
The key to understanding this is knowing how the next function retrieves the argument passed to next(), which is as the return value of the yield operator:
[rv] = yield [expression];
Independently of the value of [expression], yield will assign to rv the value passed to next().
But, here comes the tricky part: yield will only assign the value passed to next() when resuming execution from a previous iteration. As a consequence, on the first iteration, yield does not assign anything to rv.
For example, if I have this generator:
function* gen() {
// On the first iteration, yield does not return anything.
//because it returns something ONLY when execution is resumed
returnedFromYield = yield 'foo';
yield returnedFromYield;
}
returnedFromYield is undefined on the first iteration. When execution is resumed on the second iteration, yield assigns the passed value to the returnedFromYield variable, which is then returned:
g.next(1); // 'foo'
g.next(2); // 2
Let's review another example:
function* gen() {
yield yield yield 5;
}
On the first iteration, (g.next()), yield will return 5, on the second iteration, (g.next(10)) yield is going to pass 10 to the second yield. That is, yield yield yield 5; on the second iteration is equivalent to yield yield 10;, and, on the third iteration, it's equivalent to yield valuePassedToNext.
Here's an annotated example showing the logical flow and scope for the values passed to a generator's next method. The affected area of the next method call is highlighted in the corresponding color.
a: There is no yield, so argument 'one' is ignored. The generator pauses on line 5, returning the value 1.
b: Execution resumes and 'two' replaces yield on line 5, and is assigned to the yieldValue variable. Line 6 is executed. The generator pauses on line 8, returning the value 2.
c: Execution resumes and 'three' replaces yield on line 8, and is assigned to the yieldValue variable. Line 9 is executed. The generator pauses on line 11, returning the value 3.
d: Execution resumes and 'four' replaces yield on line 11, and is assigned to the yieldValue variable. Line 12 is executed. Line 14 is executed. Finally the generator is now done, returning the value undefined.
See the logs on line 28-36
How does work app.use in KOA?
When I set some generator inside app.use, everything works perfect.
How can I do the same elsewhere?
When I just execute generator manual:
var getRelationsList = function *() {
var res = yield db.relations.find({});
console.log({'inside: ': res});
}
console.log({'outside: ': getRelationsList().next()});
getRelationsList().next();
I'm getting just { 'outside: ': { value: [Function], done: false } }
This what I expect is:
{ 'outside: ': { value: {object_with_results}, done: false } }
{ 'inside: ': {object_with_results}
EDIT
I changed my code like that:
var getRelationsList = function *() {
var res = yield db.relations.find({});
console.log({'inside: ': res});
}
console.log({'outside ': co(getRelationsList)});
Now inside console log show's me good results but outside console log shows me just empty object.
Generators are a powerful tool for organizing asynchronous code, but they don't magically wait for asynchronous code to run.
What's Happening
Let's walk through your code so you can see what is happening:
getRelationsList is a generator function, that when called returns a new generator. At this point, no code in your generator function has been called (although if you were passing params they would be set). You then call .next on your generator to start execution of the generator function. It will execute up until it hits the first yield statement and return an object with the yielded value and the completion status of the generator.
It seems you understand most of that so far, but generators do not magically transform the yielded out values. When you yield out db.relations.find({}), you'll get the return value of the find function which I'm assuming is a Promise or some type of thenable:
so your 'outside' value is { value:Promise, done:false }
The reason your inside console.log never ran is that you're actually creating a new generator each time you call getRelationsList(), so when you call getRelationsList().next() again after the outside console.log you're creating a new generator and calling next, so it only executes up to the first yield, just like the call on the previous line.
In order to finish execution you must call next twice on the same instance of your generator: once to execute up to the yield and once to continue execution to the end of the function.
var gen = getRelationsList()
gen.next() // { value:Promise, done:false }
gen.next() // { value:undefined, done:true } (will also console.log inside)
You'll notice, however, if you run this, the inside console.log will be undefined. That's because the value of a yield statement is equal to the value passed to the following .next() call.
For example:
var gen2 = getRelationsList()
gen2.next() // { value:Promise, done:false }
gen2.next(100) // { value:undefined, done:true }
Outputs
{ inside:100 }
Because we passed 100 to the second .next() call and that became the value of the yield db.relations.find({}) statement which was then assigned to res.
Here's a link demoing all of this: http://jsfiddle.net/qj1aszub/2/
The Solution
The creators of koa use a little library called co which basically takes yielded out promises and waits for them to complete before passing the resolved value back into the generator function (using the .next() function) so that you can write your asynchronous code in a synchronous style.
co will return a promise, which will require you to call the .then method on to get the value returned from the generator function.
var co = require('co');
var getRelationsList = function *() {
var res = yield db.relations.find({});
console.log({'inside: ': res});
return res
}
co(getRelationsList).then(function(res) {
console.log({'outside: ': res })
}).catch(function(err){
console.log('something went wrong')
});
co also allows you to yield out other generator functions and wait for their completion, so you don't have to wrap things with co at every level and deal with promises until you're at some sort of 'top level':
co(function *() {
var list = yield getRelationsList()
, processed = yield processRelations(list)
, response = yield request.post('/some/api', { data:processed })
return reponse.data
}).then(function(data) {
console.log('got:', data)
})
Your problem is that you call getRelationsList() function multiple times which is incorrect.
Change your code to following
var g = getRelationsList();
console.log('outside: ', g.next());
g.next(); //You get your console.log('inside: .... here
Generators must be acted upon by outside code.
Under the hood koa use the co library to 'Run' the generator.
Here is how you might achieve what your wanting outside of koa:
var co = require('co');
var getRelationsList = function *() {
var res = yield db.relations.find({});
console.log({'inside: ': res});
}
co(getRelationsList).catch(function(err){});
I did a short screencast on JavaScript generators that should help you understand what's going on:
http://knowthen.com/episode-2-understanding-javascript-generators/
++ EDIT
If your using generators to program in more of an synchronous style (eliminating callbacks), then all your work needs to be done in the generator and you should use a library like co to execute the generator.
Here is a more detailed example of how you would interact with a generator, manually. This should help you understand the results your getting.
function * myGenerator () {
var a = yield 'some value';
return a;
}
var iterator = myGenerator();
// above line just instantiates the generator
console.log(iterator);
// empty object returned
// {}
var res1 = iterator.next();
// calling next() start the generator to either the
// first yield statement or to return.
console.log(res1);
// res1 is an object with 2 attributes
// { value: 'some value', done: false }
// value is whatever value was to the right of the first
// yield statment
// done is an indication that the generator hasn't run
// to completion... ie there is more to do
var toReturn = 'Yield returned: ' + res1.value;
var res2 = iterator.next(toReturn);
// calling next(toReturn) passes the value of
// the variable toReturn as the return of the yield
// so it's returned to the variable a in the generator
console.log(res2);
// res2 is an object with 2 attributes
// { value: 'Yield returned: some value', done: true }
// no further yield statements so the 'value' is whatever
// is returned by the generator.
// since the generator was run to completion
// done is returned as true
I am trying to learn how to use generators and yield, so I tried the following but it doesn't seem to be working.
I am using the following function, which contains 2 async calls:
var client = require('mongodb').MongoClient;
$db = function*(collection, obj){
var documents;
yield client.connect('mongodb://localhost/test', function*(err, db){
var c = db.collection(collection);
yield c.find(obj).toArray(function(err, docs){
documents = docs;
db.close();
});
});
return documents.length;
};
Then to make the call original call, I am doing this:
var qs = require("querystring");
var query = qs.parse("keywords[]=abc&keywords[]=123");
var total = $db("ads", {"details.keywords": {$in: query["keywords[]"]}});
console.log(total);
When I get my output back in the console, I get this:
{}
I was expecting a number such as 200. What is it that I am doing wrong?
TL;DR
For the short answer, you're looking for a helper like co.
var co = require("co");
co(myGen( )).then(function (result) { });
But Why?
There is nothing inherently asynchronous about ES6 iterators, or the generators which define them.
function * allIntegers ( ) {
var i = 1;
while (true) {
yield i;
i += 1;
}
}
var ints = allIntegers();
ints.next().value; // 1
ints.next().value; // 2
ints.next().value; // 3
The .next( ) method, though, actually lets you send data back in to the iterator.
function * exampleGen ( ) {
var a = yield undefined;
var b = yield a + 1;
return b;
}
var exampleIter = exampleGen();
exampleIter.next().value; // undefined
exampleIter.next(12).value; // 13 (I passed 12 back in, which is assigned to a)
exampleIter.next("Hi").value; // "Hi" is assigned to b, and then returned
It might be confusing to think about, but when you yield it's like a return statement; the left hand side hasn't been assigned the value yet... ...and more importantly, if you had put the var y = (yield x) + 1; the parenthesis are resolved before the rest of the expression... ...so you return, and the +1 is put on hold, until a value comes back.
Then when it arrives (passed in, via the .next( )), the rest of the expression is evaluated (and then assigned to the left hand side).
The object that's returned from each call has two properties { value: ..., done: false }
value is what you've returned/yielded and done is whether or not it's hit the actual return statement at the end of the function (including implicit returns).
This is the part that can then be used to make this async magic happen.
function * asyncGen ( id ) {
var key = yield getKeyPromise( id );
var values = yield getValuesPromise( key );
return values;
}
var asyncProcess = asyncGen( 123 );
var getKey = asyncProcess.next( ).value;
getKey.then(function (key) {
return asyncProcess.next( key ).value;
}).then(function (values) {
doStuff(values);
});
There's no magic.
Instead of returning a value, I'm returning a promise.
When the promise completes, I'm pushing the result back in, using .next( result ), which gets me another promise.
When that promise resolves, I push that back in, using .next( newResult ), et cetera, until I'm done.
Can we do better?
We know now that we're just waiting for promises to resolve, then calling .next on the iterator with the result.
Do we have to know, ahead of time what the iterator looks like, to know when we're done?
Not really.
function coroutine (iterator) {
return new Promise(function (resolve, reject) {
function turnIterator (value) {
var result = iterator.next( value );
if (result.done) {
resolve(result.value);
} else {
result.value.then(turnIterator);
}
}
turnIterator();
};
}
coroutine( myGen ).then(function (result) { });
This isn't complete and perfect. co covers extra bases (making sure all yields get treated like promises, so you don't blow up by passing a non-promise value... ...or allowing arrays of promises to be yielded, which becomes one promise which will return the array of results for that yield ...or try/catch around the promise handling, to throw the error back into the iterator... yes, try/catch works perfectly with yield statements, done this way, thanks to a .throw(err) method on the iterator).
These things aren't hard to implement, but they make the example muddier than it needs to be.
This is exactly why co or some other "coroutine" or "spawn" method is perfect for this stuff.
The guys behind the Express server built KoaJS, using Co as a library, and Koa's middleware system just takes generators in its .use method and does the right thing.
But Wait, there's more!
As of ES7, it's very likely that the spec will add language for this exact use-case.
async function doAsyncProcess (id) {
var key = await getKeyPromise(id);
var values = await getValuesPromise(key);
return values;
}
doAsyncProcess(123).then(values => doStuff(values));
The async and await keywords are used together, to achieve the same functionality as the coroutine-wrapped promise-yielding generator, without all of the external boilerplate (and with engine-level optimizations, eventually).
You can try this today, if you're using a transpiler like BabelJS.
I hope this helps.
Yield and generators have nothing to do with asynchrony, their primary purpose is to produce iterable sequences of values, just like this:
function * gen() {
var i = 0;
while (i < 10) {
yield i++;
}
}
for (var i of gen()) {
console.log(i);
}
Just calling a function with a star (generator function) merely creates generator object (that is why you see {} in console), that can be interacted with using next function.
That said, you can use generator functions as an analogue of asynchronous functions, but you need a special runner, like co.
var client = require('mongodb').MongoClient;
$db = function*(collection, obj){
var documents;
yield client.connect('mongodb://localhost/test', function*(err, db){
var c = db.collection(collection);
yield c.find(obj).toArray(function(err, docs){
documents = docs;
db.close();
});
});
return documents.length;
};
var qs = require("querystring");
var query = qs.parse("keywords[]=abc&keywords[]=123");
var total = $db("ads", {"details.keywords": {$in: query["keywords[]"]}});
console.log(total);
As is, total is the iterator for the $db generator function. You would retrieve its yield values via total.next().value. However, the mongodb library is callback based and as such, its functions do not return values, so yield will return null.
You mentioned you were using Promises elsewhere; I would suggest taking a look at the bluebird in particular its promisify functionality. Promisification inverts the callback model so that the arguments to the callback are now used to resolve the promisified function. Even better, promisifyAll will convert an entire callback based API.
Finally, bluebird provides coroutine functionality as well; however its coroutines must return promises. So, your code may be rewritten as follows:
var mongo = require('mongodb');
var Promise = require('bluebird');
//here we convert the mongodb callback based API to a promised based API
Promise.promisifyAll(mongo);
$db = Promise.coroutine(function*(collection, obj){
//existing functions are converted to promised based versions which have
//the same name with 'Async' appended to them
return yield mongo.MongoClient.connectAsync('mongodb://localhost/test')
.then(function(db){
return db.collectionAsync(collection);})
.then(function(collection) {
return collection.countAsync();});
});
var qs = require("querystring");
var query = qs.parse("keywords[]=abc&keywords[]=123");
$db('ads',{"details.keywords": {$in: query["keywords[]"]}})
.then(console.log)