Variable context issue on node.js using Q (promise) [duplicate] - javascript

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I'm using node.js with Q as promise implementation.
For some reason I have to build a few promise with a loop. In the "real" code, of course, I do not use constant in "for" loop.
I have an issue when I give i as parameter to my function buildPromiseForIdx. I expect to pass the value of i and expect the following result in the console.
-3
*3
but the code displays:
-3
*2
Here is the code:
function loop(promise, fn) {
return promise.then(fn).then(function (result) {
return !result ? loop(Q(result), fn) : result;
});
}
function buildPromiseForIdx(i) {
return getIdx(i*10).then(parseIdx);
}
// building promises for all idx page
var promises= [];
for (var i = 3 ; i >= 3 ; i--) {
log.debug('-'+i);
promises.push(loop(Q(false), function () { log.debug('*'+i);return buildPromiseForIdx(i)}));
}

The answer of the following question is also working in this case.
How do I pass the value (not the reference) of a JS variable to a function?
My loop is now:
var promises= [];
for (var i = 3 ; i >= 3 ; i--) {
log.debug('-'+i);
(function (i) {
promises.push(loop(Q(false), function () { log.debug('*'+i);return buildPromiseForIdx(i)}));
})(i);
}

Related

how to create dynamic function in javascript with for loop and its index inside function [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
var data = ["s","a"]
var asyncFunctionss = [];
for (var i in data) {
asyncFunctionss.push(function (callback) {
console.log(i);
});
}
for (var g in asyncFunctionss) {
asyncFunctionss[g]();
}
I try to run this program it give the following output.
Expected Output
0
1
Actual Output
1
1
How to achieve the Expected output ?
You need an IIFE. The reason is that as soon as a function element in asyncFunctionss is called the variable i is already 1. You could use a IIFE to remember the value of variable i:
var data = ["s","a"]
var asyncFunctionss = [];
for (var i in data) {
(function(i){
asyncFunctionss.push(function (callback) {
console.log(i);
});
})(i);
}
for (var g in asyncFunctionss) {
asyncFunctionss[g]();
}

Alternative to the 'let' keyword in a loop? [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 7 years ago.
I was having an issue where I was setting up a bunch of timeout calls and I wanted the timeout function to reference the element in the current loop.
This is what the result looked like:
var createTimedMessages = function(arr, collection){
var timeLimit = 2000;
for(var i = 0; i<arr.length; i++){
let el = arr[i];
collection.push(el);
$timeout(function removeElement(){
collection.removeMatch(el);
}, timeLimit);
}
}
but I realized that this wouldn't work with some slightly older browsers because of lack of support for the let keyword. What is a good workaround?
Note: This is in angular, hence the $timeout rather than setTimeout.
Use a IIFE:
var createTimedMessages = function(arr, collection) {
var timeLimit = 2000;
for (var i = 0; i < arr.length; i++) {
(function(el) {
collection.push(el);
$timeout(function removeElement() {
collection.removeMatch(el);
}, timeLimit);
})(arr[i]);
}
}
Self-executing functions should solve the problem:
(function(el, timeLimit) {
$timeout(/* your code */);
})(arr[i], timeLimit);

Javascript iterator design pattern [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
How do JavaScript closures work?
(86 answers)
Closed 7 years ago.
I am confused why the following code snippet has (i) at the end of it:
for (var i = 0; i < 10; i += 1) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000);
})(i);
}
Ive seen it in production code Ive worked on--I just can intuit why it's necessary.
You are defining an inline function, so you could force the i parameter to be in the local scope at the time of the execution of the console.log statement. By adding the parameter, you are creating a self executing function. Similar would be the following statements, which might be better to read...
function logmeWithTimeOut(value) {
setTimeout(function() { console.log(value); }, 1000);
}
for (var i = 0; i < 10; i++) {
logmeWithTimeout(i);
}
Though I might prefer
function logmeWithTimeout(value) {
console.log(value);
}
for (var i = 0; i < 10; i++) {
setTimeout(logmeWithTimeout.bind(undefined, i), 1000);
}
It forces the i to be in local scope, otherwise your log would print only 11
Because you are defining a function inside the parenthesis, and then you are calling it passing i as parameter.
If you didn't put the (i) there, you would just define a function but never call it.

How can I write a JS callback function that remembers the old value of a changing variable? [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
Here's a simplification of my JS program. mylist is an array of strings and MyAsync is a function that takes an object and arranges for the supplied callback to be called at a later time.
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
MyAsync(mylist[myindex], function () { alert(myindex); });
}
When there's ten items in mylist, the result is two alert messages each showing "10". Okay, it's clearly using the value of myindex after the loop finishes. So I make a slight change...
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
var copyindex = myindex;
MyAsync(mylist[myindex], function () { alert(copyindex); });
}
Now, each alert shows "9".
How do I please arrange for the callback function to know what myindex was at the time MyAsync was invoked?
Asynchronously, billpg.
Yeah, as the comments and not making functions in a loop for the reason you are experiencing.
We can use a recursive function instead :
var len = mylist.length;
function asyncLoop(index) {
MyAsync(mylist[index], function () {
if(index < len) {
asyncLoop(++index);
}
});
}
asyncLoop(0);
As comments , - firing them all off at the same time* ( *- quick as a loop can run ). and keeping track of the array count ...
function asyncDo(index) {
MyAsync(mylist[index], function () {
/* we have access to the array index here */
console.log(index);
});
}
for ( var i=0, len=mylist.length; i<len; ++i) { asyncDo(i); }
You can use closures to do this: here is some code that I think demonstrates what you want, printing out 0 .. 9.
var funcs = [];
for(var i = 0; i < 10; i++){
funcs.push( (function(j){
return function(){
console.log(j);
};
})(i));
}
funcs.forEach(function(f){
f();
});
The idea is that in returning a function to be added to the list, the value of i is captured when that function was constructed from the parameter to the outer function.
Here's an SO post that helped me with this: JavaScript closures vs. anonymous functions

Understanding closures in JavaScript [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 9 years ago.
Consider this
fs=[];
for(var i = 0; i < 3; i++){
fs.push(function(){
return i;
});
}
console.log(fs[0](),fs[1](),fs[2]())
I thought that i would be in the closure of the function so that this would print "0 1 2", but nope... it prints "3 3 3".
Why doesn't this work? And is there any way to make this work?
You are actually pushing three instances of the same anonymous function into your 'fs' array. Then your log statement calls that function three times. At the time you are calling it, the loop has completed and the value of 'i' within the closure is 3, so that's what is returned.
I'm not sure what you mean by "work", but maybe something like this is what you mean:
fs = [];
function closureFunc(myVal) {
return function () {
return myVal;
}
}
for (var i = 0; i < 3; i++) {
fs.push(closureFunc(i));
}
console.log(fs[0](), fs[1](), fs[2]());
This creates three separate closures where the function you are pushing has the scope of the declaring function "closureFunc". Within those closures the myVal is set to the value that was passed in.
Javascript doesn't have a notion of block scope, it only has function scope. Hence the placement of the var i is meaningless in terms of lifetime. It may as well have been the first line in the method.
In order to fix this you need to declare a new scope that holds a separate i value
fs=[];
var makeFunc = function(j) { return function() { return j; } }
for(var i = 0; i < 3; i++){
fs.push(makeFunc(i));
}

Categories

Resources