I have a for loop in a function in the structure
func(var, callback) {
for(i = 0; i < len; i++) {
validate(var, function(value) {
if (!value) { callback(value) }
}
}
callback(true);
}
Where the function validate returns a boolean. I would only like to call my callback with true if it has not been called before. I tried putting a return after callback(value) but that didn't help.
Set a flag:
function func(foo, callback) {
var called = false;
for(var i = 0; i < len; i++) {
validate(foo, function(value) {
if (!value) {
called = true;
callback(value);
}
})
}
if (!called) {
callback(true);
}
}
Related
there is no output to the code even tho it is being called at the bottom. How can i fix this?
<script>
function hasMatch(item) {
function inList() {
var List = [1,2,3,4];
for (i = 0; i<List.length; i++){
if (List[i] = item) {
return true;
} else {
return false;
}
}
}
inList();
}
hasMatch(2);
hasMatch();
</script>
You need to return the output of inList
function hasMatch(item) {
function inList() {
var List = [1,2,3,4];
for (i = 0; i<List.length; i++){
if (List[i] = item) {
return true;
} else {
return false;
}
}
}
return inList();
}
console.log(hasMatch(2));
console.log(hasMatch())
Try to do like this:
function hasMatch(item) {
function inList() {
var List = [1,2,3,4];
for (var i = 0; i<List.length; i++){
if (List[i] == item) {
return true;
}
}
return false;
}
return inList(item);
}
console.log (hasMatch(2));
I am try to call a nesting function like below:
function public(val) {
if (val == "exist") {
function runList() {
for (var i = 0; i < arguments.length; i++) {
arguments[i]();
}
}
}
public.runList = runList;
}
var publicExist = "exist";
function test() {
console.log(test)
}
function testE() {
console.log(testE)
}
public(publicExist);
public.runList(test, testE);
I want to fire function, but these codes only show the text, how can I do?
You forgot to put quotes around 'test' and 'testE', which I am assuming you wanted to log to the console as strings.
function public(val) {
if (val == "exist") {
function runList() {
for (var i = 0; i < arguments.length; i++) {
arguments[i]();
}
}
}
public.runList = runList;
}
var publicExist = "exist";
function test() {
console.log('test')
}
function testE() {
console.log('testE')
}
public(publicExist);
public.runList(test, testE);
Just add quotes in test and testE method's console -
function public(val) {
if (val == "exist") {
function runList() {
for (var i = 0; i < arguments.length; i++) {
arguments[i]();
}
}
}
public.runList = runList;
}
var publicExist = "exist";
function test(){
console.log('test')
}
function testE(){
console.log('testE')
}
public(publicExist);
public.runList(test,testE);
extend is based on each function:
function each(collection,iterator) {
if (Array.isArray(collection)) {
for (var i=0; i < collection.length; i++) {
iterator(collection[i]);
}
} else {
for (var key in collection) {
iterator(collection[key]);
}
}
}
after I check underscore.js, apparently the extend function takes two parameters...but im not sure how to rewrite the function so it can work?
function extend(newProperty) {
each(arguments,function(source) {
each(source,function(value,key) {
newProperty[key]=value;
})
})
return newProperty;
}
var iceCream = {flavor: "chocolate"};
extend(iceCream,{sprinkles: "lots"});
//==> { flavor: 'chocolate', undefined: 'chocolate' }
Your each function is only providing the element of the collection, it should also provide the key. Try this.
function each(collection,iterator) {
if (Array.isArray(collection)) {
for (var i=0; i < collection.length; i++) {
iterator(collection[i], i);
}
} else {
for (var key in collection) {
iterator(collection[key], key);
}
}
}
here's the code I currently using,
function loopArrayWithAsync(array, doSthWithElement, finalCallback) {
var count = 0;
var _data = [];
var _errs = [];
for (var i = 0; i < array.length; i++) {
doSthWithElement(array[i], function (err, data) {
count++;
if (err) {
_errs.push(err);
}
if (data) {
_data.push(data);
}
if (count === data.length) {
finalCallback(_errs, _data);
}
}
}
}
then, I will use the function in this way:
loopArrayWithAsync(array, function (element, finish) {
// element - element in the array
asyncFunc(element, function (err, result) {
if (err) {
finish(err);
} else {
finish(null, result);
}
});
}, function (errs, finalData) {
// when the for loop is finished,
// i.e. (count === data.length)
// this callback will be executed
// errs - array of err from the above callback function
// finalData - array of result from the above callback function
outerCallback(errs, finalData);
});
with this implementation, I can loop through an array with async function and execute the callback function when all elements in the array have been processed.
but now I want to add a delay/interval feature to loopArrayWithAsync()
something like loopArrayWithAsync(array, {interval : 1000}, function (element, finish) {..., after it processed the first element, it should wait for 1000ms, then starts to process the second element, and vice versa...
I've found another question talking about adding delay to for loop
but it seems to be more complicated while dealing with async functions.
Any answers will be appreciated
============================== update ==============================
this is the function after refactoring,
function loopArrayWithAsync(array, options, doSthWithElement, finalCallback) {
if (isFunction(options)) {
finalCallback = doSthWithElement;
doSthWithElement = options;
options = {};
}
options.interval = options.interval || 0;
options.oneByOne = options.oneByOne || false;
var _data = [];
var _errs = [];
var count = 0;
var length = array.length;
var i = 0;
(function handleIteration() {
if (i < length) {
var element = array[i];
doSthWithElement(element, function (err, data) {
if (err) {
_errs.push(err);
}
if (data) {
_data.push(data);
}
count++;
if (count === length) {
finalCallback(_errs, _data);
} else if (options.oneByOne) {
if (options.interval) {
setTimeout(handleIteration, options.interval);
} else {
process.nextTick(handleIteration);
}
}
});
i++;
if (!options.oneByOne) {
if (options.interval) {
setTimeout(handleIteration, options.interval);
} else {
process.nextTick(handleIteration);
}
}
}
}());
};
so that I can use the function in this way now:
loopArrayWithAsync(array, {interval : 1000}, function (element, finish) {
asyncFunc(element, function (err, result) {
if (err) {
finish(err);
} else {
anotherAsyncFunc(result, function (err, doc) {
if (err) {
finish(err);
} else {
finish(null, doc);
}
});
}
});
}, function (errs, finalData) {
outerCallback(errs, finalData);
});
or
loopArrayWithAsync(array, {oneByOne : true}, function (element, finish) {...
loop through the elements one by one
loopArrayWithAsync(array, {interval : 5000, oneByOne : true}, function (element, finish) {...
loop through the elements one by one and with 5 seconds delay
available options :
interval is the amount of milliseconds between each iteration, default : 0
If oneByOne is true, the method would only proceed to the next element until finish has been invoked for the current element, default : false
The code suits my case now, but I will still try the suggested libraries to make life easier, thank you
Please leave a comment if you found that the code can be further improved, looking forward to any suggestions!
As suggested by #thefourtheye you can use the concept of Promises, and Bluebird is a fast and good library for this. Promise.settle lets you resolve and reject your promises and then inspect the result.
function loopArray(array) {
var arrayOfPromises = [];
for (var i = 0; i < array.length; i++) {
arrayOfPromises.push(doSomethingAsync(array[i]));
}
Promise.settle(arrayOfPromises).then(function (results) {
console.log("All async calls done! You can inspect the result!");
console.log(results);
});
}
function doSomethingAsync(item) {
return new Promise(function(resolve, reject){
//Do you async work here!
console.log("Entering async function call " + item);
if(item === "three"){
reject("bad value!");
}
resolve(item + " promise done!");
});
}
loopArray(["one","two","three"]);
I made a JSFiddle of the below example. Working with asynchronous functions, promises can help you out a lot, so I'd really suggest you look into it.
You can use a local function to make the asynchronous loop. For the next iteration the function calls itself with a delay:
function loopArrayWithAsync(array, doSthWithElement, finalCallback, delay) {
var _data = [], _errs = [], i = 0;
loop();
function loop() {
doSthWithElement(array[i], function (err, data) {
if (err) {
_errs.push(err);
}
if (data) {
_data.push(data);
}
i++;
if (i === array.length) {
finalCallback(_errs, _data);
} else {
window.setTimeout(loop, delay);
}
}
}
}
To start the calls at a certain interval instead of having a delay between calls, just use setInterval with different times:
function loopArrayWithAsync(array, doSthWithElement, finalCallback, delay) {
var _data = [], _errs = [], count = 0;
for (var i = 0; i < array.length; i++) {
window.setTimeout(function() {
doSthWithElement(array[i], function (err, data) {
if (err) {
_errs.push(err);
}
if (data) {
_data.push(data);
}
count++;
if (count === array.length) {
finalCallback(_errs, _data);
}
});
}, i * delay);
}
}
I know I'm leaving out the -1 option when value can't be found, but why doesn't it work when the value is in the Array? It should be returning 1, but is returning undefined.
function each(collection, callback) {
if (Array.isArray(collection)) {
for (var i = 0; i < collection.length; i++) {
callback(collection[i], i, collection);
}
}
else {
for (var prop in collection) {
callback(collection[prop], prop, collection);
}
}
}
function indexOf(array, value) {
each(array, function(e, index) {
if (e === value) {
return index;
}
})
}
console.log(indexOf([1, 2, 3, 4, 5], 2)); ---->>> undefined;
You're returning the value of index within the callback, not within the indexOf() function itself.
Try this implementation:
function indexOf(array, value) {
var returnVal = -1;
each(array, function(e, index) {
if (e === value) {
returnVal = index;
return false;
}
});
return returnVal;
}
EDIT: As Barmar pointed out, this will return the index of the last occurrence of the element, to return the index of the first occurrence, you'll also have to update each() to be:
function each(collection, callback) {
if (Array.isArray(collection)) {
for (var i = 0; i < collection.length; i++) {
if (callback(collection[i], i, collection) === false) break;
}
}
else {
for (var prop in collection) {
if (callback(collection[prop], prop, collection) === false) break;
}
}
}
function indexOf(array, value) {
each(array, function(e, index) {
if (e === value) {
return index;
}
})
}
The return here is returning from the function that is being passed to each and not from your indexOf function. You need to somehow get that value outside of that function scope to return. With your current implementation of each, you would not be able to break the loop, so you would have to do something like this:
function indexOf(array, value) {
var result = -1;
each(array, function(e, index) {
if (e === value) {
result = index;
}
})
return result;
}
http://jsfiddle.net/efzogzxq/
Your indexOf() function isn't returning anything. The callback returns the index if found, but you're not doing anything with that value. You could do this:
for (var i = 0; i < collection.length; i++) {
var result= callback(collection[i], i, collection);
if (result) return result;
}
You'll want to return the index if found. Also, you need to exit the loop once you've found the value, otherwise you're doing a lastIndexOf instead of indexOf.
function each(collection, callback) {
if (Array.isArray(collection)) {
for (var i = 0; i < collection.length; i++) {
if (callback(collection[i], i, collection) === true) {
return;
}
}
}
else {
for (var prop in collection) {
if (callback(collection[prop], prop, collection) === true) {
return;
}
}
}
}
function indexOf(array, value) {
var foundIndex = -1;
each(array, function(e, index) {
if (e === value) {
foundIndex = index;
return true;
}
});
return foundIndex;
}
The indexOf function is always returning undefined because the you are only returning a value from the callback function, not the indexOf function.
Try this:
function indexOf(array, value) {
var i;
each(array, function(e, index) {
if (e === value) {
i = index;
}
})
return i;
}