Calling a function with a promise into a foreach - javascript

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

Related

node.js - nesting request, wait until request function is done

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.

ES6 yield (yield 1)(yield 2)(yield 3)()

function* generatorFunction() {
yield (yield 1)(yield 2)(yield 3)();
}
var iterator = generatorFunction();
// [1, 2, 3]
var iteratedOver = [iterator.next().value, iterator.next().value, iterator.next().value];
I'm not sure how this works.
yield doesn't return a function reference, so what are the parenthetical statements like (yield 2) doing - are they fat arrow anonymous functions without bodies? How are they called using partial application like that?
I'm missing something here, can someone explain?
Update: Tried on three browsers, Chrome 50.0.2661.86, Safari 9.1 (50.0.2661.86), Firefox 44.0.2, all perform without errors.
ESFiddle also executes it without errors.
Commenters report Babel executes without errors as well.
The source of the question is from http://tddbin.com/#?kata=es6/language/generator/send-function, the second kata.
I'm not sure how this works.
Uh, yeah, it shouldn't work. It's only working because of a bug in Babel.
yield doesn't return a function reference, so what are the parenthetical statements like (yield 2) doing - are they fat arrow anonymous functions without bodies? How are they called using partial application like that?
No, it's really just standard function application, no magic. yield could return a function reference, and when it does this might work. When it doesn't, it will throw an exception on the third .next() call.
As an example for a working version:
function* generatorFunction() {
yield (yield 1)(yield 2)(yield 3)();
}
var test = (a) => {
console.log(a);
return (b) => {
console.log(b);
return (c) => {
console.log(c);
return 4;
};
};
};
var iterator = generatorFunction();
iterator.next(); // {value: 1, done: false}
iterator.next(test); // {value: 2, done: false}
iterator.next("a"); // "a" {value: 3, done: false}
iterator.next("b"); // "b" undefined {value: 4, done: false}
iterator.next("d"); // {value: undefined, done: true}
So how does this work? Those nested/chained yield statements should better be written as
function* generatorFunction() {
let fn1 = yield 1;
let a = yield 2;
let fn2 = fn1(a);
let b = yield 3;
let fn3 = fn2(b);
let res = fn3();
let d = yield res;
return undefined;
}
Commenters report Babel executes without errors as well.
That's because of a babel bug. If you check the transpiler output, it actually behaves like
function* generatorFunction() {
let fn1 = yield 1;
let a = yield 2;
let b = yield 3;
// these are no more executed with only 3 `next` calls
let fn2 = fn1(a);
let fn3 = fn2(b);
let res = fn3();
let d = yield res;
return undefined;
}

how to use co with a named function?

So I am trying to use co to wrap around MongoDB methods that return promises
eg
http://mongodb.github.io/node-mongodb-native/2.0/reference/ecmascript6/crud/
I see co being used like:
co(function*() {
which seems like an anonymous function. Fine in the main body of your code, but is there a way to get at the values yielded inside?
eg to basically get at the results of the co routine:
If I could do:
let wrap = co(function* (collName) {
let res = yield collection.findOne({});
yield res;
});
and then elsewhere
let res = wrap("Topics");
but I get
TypeError: wrap is not a function
Tried also:
co(function* wrap(collName) {
...
co.call(this, wrap("Topics"));
let wrap = co.wrap(function* (collName) { ...
but still no luck.
I think what you're looking for is the co.wrap function.
let wrap = co.wrap(function* (collName) {
let res = yield collection.findOne({});
yield res;
});
Then you can use it in the way you want
let res = wrap("Topics");

Generators in KOA

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

Javascript ES6 Generators

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

Categories

Resources