I'm diving into javascript generators and I'm really confused.
I'm using node#0.11.x to run this example:
function find() {
process.nextTick(function() {
it.next(1);
});
};
var it = (function* main() {
var k = yield find();
console.log(k);
})();
it.next();
Is there a way to grab the reference to next function inside the generator?
Something like:
function find(next) {
process.nextTick(function() {
next(1);
});
};
(function* main() {
var k = yield find(this.next);
console.log(k);
})().next();
To answer your question directly, you can't because this inside a generator function is not the generator instance, it is the context of the function call. You could do:
function find(next) {
process.nextTick(function() {
next(1);
});
};
var it = (function* main() {
var k = yield find(it.next.bind(it));
console.log(k);
})();
it.next();
but that's pretty hard to follow. Generally this would be accomplished with a coroutine library like co. With that, you would yield a promise, and when the promise is resolved, co will call .next with the value that the promise resolved with.
var co = require('co');
function find(){
return new Promise(function(resolve){
process.nextTick(function(){
resolve(1);
});
});
}
co(function * (){
var k = yield find();
console.log(k);
});
Related
I'm getting this error:
"lambdaCallbackWith": [
"TypeError: #<Promise> is not a function",
"at Array.forEach (<anonymous>)",
When i ran the code below:
var resizeVolume = function* (event, context) {
var co = require('co');
volumes.forEach(co(function *(volume) {
yield eC2.setNewVolume(volume.VolumeId, volumeSize);
}));
}
The error occurred in foreach, i added the CO but no success.
The code without CO show an error saying the yield is a reserved word.
yield can only be used in a generator function. That's why
volumes.forEach(() => {
yield ...
})
Won't work.
You will need a library to use a generator in a forEach loop such as co-foreach.
If you don't want to you can use a regular for loop like this:
const co = require('co');
var resizeVolume = function* (event, context) {
co.wrap(function *() {
for (let i = 0 ; i < volumes.lenght ; i++) {
const volume = volumes[i];
yield eC2.setNewVolume(volume.VolumeId, volumeSize);
}
});
}
The following implements a control flow wrapper co enabling asynchronous code to be delineated only by the yield keyword.
Is this basically what async/await does under the hood in ESwhatever?
co(function*() {
console.log('...');
yield one();
console.log('...');
yield two();
})
function co(gFn) {
var g = gFn();
return Promise.resolve()
.then(go);
function go() {
var result = g.next();
if(result.done) {
return;
}
if(isPromise(result.value)) {
return result.value.then(go); // Promises block until resolution.
}
return Promise.resolve(result);
}
}
function isPromise(o) {
return o instanceof Promise;
}
function one() {
return new Promise(resolve => setTimeout(() => (console.log('one'), resolve()), 1000));
}
function two() {
return new Promise(resolve => setTimeout(() => (console.log('two'), resolve()), 1000));
}
Edit:
In light of the responses I updated to take into consideration return values:
co(function*() {
console.log('...');
const result1 = yield one();
console.log('result1: ', result1);
const result2 = yield two();
console.log('result2: ', result2);
const result3 = yield[one(), two()];
console.log('result3: ', result3);
const result4 = yield{
one: one(),
two: two()
};
console.log('result4: ', result4);
})
function co(gFn) {
var g = gFn();
return Promise.resolve().then(go);
function go() {
var result = g.next(...arguments);
if (isPromise(result.value)) {
return result.value.then(go);
}
if (Array.isArray(result.value)) {
return Promise.all(result.value).then(go);
}
if (isObject(result.value)) {
var o = {};
var promises = Object.keys(result.value).map(k=>result.value[k].then(r=>o[k] = r));
return Promise.all(promises).then(()=>o).then(go);
}
return Promise.resolve(result);
}
}
function isPromise(o) {
return o instanceof Promise;
}
function isObject(val) {
return val && (Object === val.constructor);
}
function one() {
return new Promise(resolve=>setTimeout(()=>(console.log('one'),
resolve('result 1')), 1000));
}
function two() {
return new Promise(resolve=>setTimeout(()=>(console.log('two'),
resolve('result 2')), 1000));
}
Is this basically what async/await does under the hood in ESwhatever?
Not really. It's a different approach for doing sorta the same thing. What async/await turn into is more like
async function foo() {
const bar = await Bar();
bar++;
const baz = await Baz(bar);
return baz;
}
becomes
function foo() {
return Bar()
.then(bar => {
bar++;
return Baz(bar)
.then(baz => {
return baz;
});
});
}
Stage 3 Draft / January 26, 2016
Async Functions provides examples of three patterns; Promise; Generator; Async Functions; where the distinct approaches essentially produce the same result
Examples#
Take the following example, first written using Promises. This code
chains a set of animations on an element, stopping when there is an
exception in an animation, and returning the value produced by the
final succesfully executed animation.
function chainAnimationsPromise(elem, animations) {
let ret = null;
let p = currentPromise;
for(const anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
})
}
return p.catch(function(e) {
/* ignore and keep going */
}).then(function() {
return ret;
});
}
Already with promises, the code is much improved from a straight callback style, where this sort of looping and exception handling is
challenging.
Task.js and similar libraries offer a way to use generators to further
simplify the code maintaining the same meaning:
function chainAnimationsGenerator(elem, animations) {
return spawn(function*() {
let ret = null;
try {
for(const anim of animations) {
ret = yield anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
});
}
This is a marked improvement. All of the promise boilerplate above and beyond the semantic content of the code is removed, and the
body of the inner function represents user intent. However, there is
an outer layer of boilerplate to wrap the code in an additional
generator function and pass it to a library to convert to a promise.
This layer needs to be repeated in every function that uses this
mechanism to produce a promise. This is so common in typical async
Javascript code, that there is value in removing the need for the
remaining boilerplate.
With async functions, all the remaining boilerplate is removed,
leaving only the semantically meaningful code in the program text:
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(const anim of animations) {
ret = await anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
}
I use the following code
request(firstparams, function () {
var secondparams = {
// ******
};
request(secondparams, function () {
for (i=0; i<3; i++) {
var thirdparams = {
// ******
};
request(thirdparams, function () {
console.log('foo');
});
}
console.log('bar');
});
});
and want to get the result like:
foo
foo
foo
bar
but the result is:
bar
foo
foo
foo
Sorry for my poor English, if there is something ambiguity,I would try my best to explain. Thanks a lot ^ ^
The easies way to do what you want would be to use 'async' module which is the classical module to handle async problems.
To run 3rd calls in parallel and log 'bar' after each of them is finished you would do something like this:
const async = require('async');
let asyncFunctions = [];
for (let i = 0; i < 3; i+= 1) {
let thirdParams = {...};
asyncFunctions.push(function (callback) {
request(thirdparams, function (err, data) {
console.log('foo');
callback(err, data);
});
});
}
async.parallel(asyncFunctions, function (err, data) {
console.log('bar');
});
You are using callbacks. But there are also other ways to handle asynchrony in node.js like: promises, generators and async/await functions from ES7.
I think that may be useful for you do check out some articles like this one.
I have a nodejs library written using the async/await module. I try to consume it from a library which uses regular callbacks. Here is a sample code:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async (function() {
var resultA = await (Promise.promisify(bar));
return 111;
})
function bar(callback) {
setTimeout(callback, 2000)
}
function moo() {
var f = async.cps(foo)
f(function(err, res) {
console.log(res)
})
}
moo()
I expected console.log to print 111 but instead it prints:
{ _bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_progressHandler0: undefined,
_promise0: undefined,
_receiver0: undefined,
_settledValue: undefined }
btw if I inline the foo implementation in the "async.cps" line it works (but this is not an option since its an external library).
Any idea?
I've looked at the library your using, and by the look of it (there isn't much, and certainly no working samples), you're not using it correctly.
async(fn) will return a function that accepts some input values and upon execution will return a promise (Probably standard Promises/A+). Inside, it will call fn with the input parameters, and will resolve the returned promise when fn has returned.
async.cps(...) will return a function that accepts some input values and a node style callback function (function (err, res)) and upon execution will return a void (undefined). Inside, it will call fn with the input parameters, and will call the callback function when fn has returned with the appropriate values.
what your code does is create a function with async(fn), then pass this function to async.cps(..) as if you called async.cps(async(fn)), but that doesn't make any sense.
What you could do if you wanted to "convert" a promise to a node style callback function (unpromisifying!) using this library is this:
function moo() {
var f = async.cps(function() {
return await (foo())
})
f(function(err, res) {
console.log(res)
})
}
You double-asynced the foo function. Here are your options, depending on whether you can modify the declaration of foo or not:
Leave foo async, and create a function f that accepts a node-style callback using cps:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
var f = async.cps(function() {
return await(foo());
});
f(function(err, res) {
console.log(res);
});
}
moo();
Leave foo async, and use an async moo:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
var moo = async(function() {
try {
var res = await(foo());
console.log(res);
} catch (err) {
}
});
moo();
Make foo already cps at the declaration:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async.cps(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
foo(function(err, res) {
console.log(res);
});
}
moo();
How can I perform dynamic chaining in Javascript Promises, all the time I have seen only hardcoding of the calls for eg., (promise).then(request/functionName).then(request/functionName)
Given an array functions that all return promises, you can use reduce() to run them sequentially:
var myAsyncFuncs = [
function (val) {return Promise.resolve(val + 1);},
function (val) {return Promise.resolve(val + 2);},
function (val) {return Promise.resolve(val + 3);},
];
myAsyncFuncs.reduce(function (prev, curr) {
return prev.then(curr);
}, Promise.resolve(1))
.then(function (result) {
console.log('RESULT is ' + result); // prints "RESULT is 7"
});
The example above uses ES6 Promises but all promise libraries have similar features.
Also, creating the array of promise returning functions is usually a good candidate for using map(). For example:
myNewOrmModels.map(function (model) {
return model.save.bind(model);
}).reduce(function (prev, curr) {
return prev.then(curr);
}, Promise.resolve())
.then(function (result) {
console.log('DONE saving');
});
One option is to utilize the properties of objects and the ability to invoke them via strings.
I wrote a small sample Here and posted it below.
The idea is that you have the set of functions that you wish to run set in some namespace or object, as I did in 'myNamespace':
myNamespace = {
"A": function() {return "A Function";},
"B": function() {return "B Function";},
"C": function() {return "C Function";}
}
Then your main promise would run and somehow (via inputs, ajax, prompts, etc.) you would get the string value of the function you want to have run, which isn't known until runtime:
My main promise uses a prompt to get a letter from the user:
var answer = prompt('Starting. Please pick a letter: A,B,C');
if(myNamespace[answer] === undefined)
{
alert("Invalid choice!");
reject("Invalid choice of: " + answer);
}
else
{
resolve(answer);
}
In the next 'then' I use that value (passed via the resolve function) to invoke the function:
.then(function(response) {
funcToRun = myNamespace[response]();})
Finally, I output to html the result of my dynamic function call and I use some recursive fun to make it more interactive and demonstrate that it is dynamic:
.then(function(){
document.getElementById('result').innerHTML = funcToRun;})
.then(function(){
if(prompt("Run Again? (YES/NO)")==="YES")
{
doWork();
}
});
myNamespace = {
"A": function() {return "A Function";},
"B": function() {return "B Function";},
"C": function() {return "C Function";}
}
function doWork()
{
var funcToRun;
new Promise(function(resolve,reject) {
var answer = prompt('Starting. Please pick a letter: A,B,C');
if(myNamespace[answer] === undefined)
{
alert("Invalid choice!");
reject("Invalid choice of: " + answer);
}
else
{
resolve(answer);
}
})
.then(function(response) {
funcToRun = myNamespace[response]();})
.then(function(){
document.getElementById('result').innerHTML = funcToRun;})
.then(function(){
if(prompt("Run Again? (YES/NO)")==="YES")
{
doWork();
}
});
}
doWork();
<div id="result"></div>
Since promises unwrap, just continue to add then statements and it will continue to be chained together
function asyncSeries(fns) {
return fns.reduce(function(p, fn) {
return p.then(fn);
}, Promise.resolve());
}
Recursively is a pretty cool way to do it as well :)
function countTo(n, sleepTime) {
return _count(1);
function _count(current) {
if (current > n) {
return Promise.resolve();
}
return new Promise(function(resolve, reject) {
console.info(current);
setTimeout(function() {
resolve(_count(current + 1));
}, sleepTime);
});
}
}
This is ES7 way.
Let's say you have multiple promises defined in an array.
var funcs = [
_ => new Promise(res => setTimeout(_ => res("1"), 1000)),
_ => new Promise(res => setTimeout(_ => res("2"), 1000))
}
And you want to call like this.
chainPromises(funcs).then(result => console.log(result));
You can use async and await for this purpose.
async function chainPromises(promises) {
for (let promise of promises) { // must be for (.. of ..)
await promise();
}
}
This will execute the given functions sequentially(one by one), not in parallel. The parameter promises is an array of functions, which return Promise.
Plunker: http://plnkr.co/edit/UP0rhD?p=preview
I think the simplest way is:
const executePromises = function(listOfProviders){
const p = Promise.resolve(null);
for(let i = 0; i < listOfProviders.length; i++){
p = p.then(v => listOfProviders[i]());
}
return p;
};
I believe the above is basically equivalent to:
const executePromises = async function(listOfProviders) {
for(let i = 0; i < listOfProviders.length; i++){
await listOfProviders[i]();
}
};
This solution based on usage promises of introduced in the EcmaScript 6 (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise), so before use it see table browser`s support https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Browser_compatibility
Code
var f1 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function1 is done');
}
var f2 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function2 is done');
}
var f3 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function3 is done');
}
var f4 = function(){
for (var i = 0; i < 800000000; i++) {}
console.log('Function4 is done');
}
callbacks = function(){
// copy passed arguments
var callbacks = arguments;
// create array functions
var callbacks = Object.keys(callbacks).map(function(el){ return callbacks[el] });
var now = Date.now();
callbacks.reduce(function(previousPromise, currentFunc){
return previousPromise.then(
function(){
currentFunc();
var seconds = (Date.now() - now) / 1000;
console.log('Gone', seconds, 'seconds');
}
)
}, Promise.resolve());
}
callbacks(f1, f2, f3, f4);
Result in Chrome console (values seconds will be different):
Function1 is done
Gone 1.147 seconds
Function2 is done
Gone 2.249 seconds
Function3 is done
Gone 3.35 seconds
Function4 is done
Gone 4.47 seconds
Notes:
It is does not work if a function contains a timer (for this problem
I try also jQuery`s $Callbacks, $.Ajax and $.When but it not help.
The only decision, what I found, usage resolve() in callback of a
timer, but it is not acceptable if you have completed functions.).
Testing environment
$ google-chrome --version
Google Chrome 53.0.2785.116
I just had a problem with my api provider that doing Promise.all() would end up in concurrency db problems..
The deal with my situation is that i need to get every promise result in order to show some "all ok" or "some got error" alert.
And i don't know why .. this little piece of code who uses reduce when the promises resolved i couldn't get my scope to work (too late to investigate now)
$scope.processArray = function(array) {
var results = [];
return array.reduce(function(p, i) {
return p.then(function() {
return i.then(function(data) {
results.push(data);
return results;
})
});
}, Promise.resolve());
}
So thanks to this post http://hellote.com/dynamic-promise-chains/ I came with this little bastard.. It's not polished but it's working all right.
$scope.recurse = function(promises, promisesLength, results) {
if (promisesLength === 1) {
return promises[0].then(function(data){
results.push(data);
return results;
});
}
return promises[promisesLength-1].then(function(data) {
results.push(data);
return $scope.recurse(promises, promisesLength - 1, results);
});
}
Then i invoke the function like this:
var recurseFunction = $scope.recurse(promises, promises.length, results);
recurseFunction.then(function (response) { ... });
I hope it helps.
To build on this answer, if you want to return the result of all those promises, too:
async function chainPromises(promises) {
let results = [];
for (let promise of promises) {
let result = await promise();
results.push(result);
}
return results;
}
Check the following tutorial for
programmatic (dynamic) chaining of javascript/node.js promises and
Promise chaining using recursive functions
Programmatic-Chaining-and-Recursive-Functions-with-JavaScript-Promise