Pass progress bar through async.series - nodeJs - javascript

Right im trying to get progress from a list of tasks run through async series
module.exports = update;
function update(){
// Require Deps
var async = require('async');
var progress = require('progress);
var tasks = [task1,task2,task3];
// Create the progress bar using the list of tasks
// as the length of the bar
var bar = new progress(':current/:total [:bar] :task', {
total: tasks.length
});
//Run async series using the array of tasks
async.series(tasks,function(err,result){
// Do something with the results or errors
})
};
var task1 = function(callback){
callback();
};
var task2 = function(callback){
callback();
}
This is a very simple version of my code.
The Question
How can i pass the bar to each of the functions or 'through' the functions and callbacks to that on success of each task im able to use
bar.tick({'task': tasks[bar.curr]});
everything i try I get bar not defined so tried passing bar into the functions with the callback function(callback, bar) and then i get tick not defined
Im new to nodeJs and well js all together so please be gentle
NOTE what im trying to achieve is to complete a list of functions displaying the current task in a progress bar
Ive read the docs and looked at the examples for progress and of async but still can;t make heads or tails of it
Am I close or is there a better way

You should add bar.tick, every time you want to update the current task in the taskbar. For example:
var task1 = function(callback){
bar.tick({bar:'Finish First Task'})
callback();
};
All your functions (task1,task2) should be declared INSIDE of update function, otherwise they will not be able to access the bar variable.

It's little complicated, I'm sorry. What we doing is to make new function instead of the functions in the array. The new function we call the original function, and when the original function finish (callback), it will call the progress.tick, after that it will run the original callback function.
var tasks=[task1,task2,task3]
for (var i in tasks){
(function(orgFunc,i){ // This Function will be run on task1,task2,task3. `i` will be 0,1,2, `orgFunc` will be the original function.
tasks[i]=function(next){ // Replace the original function with new function
orgFunc(funtion(){ // Call the original function
bar.tick({bar:'Finish Task #' + i})
next.apply(null,arguments) // Call the callback.
})
}}).bind(null,tasks[i],i)
}

I am not sure its the best solution, but when doing having callbacks and requesting a result, I have some kind of counter which I then check in my "final" callback:
i.e. have a global (before function update())
var tasksStatus = {task1:false,task2:false,task3:false};
and then in each task function set that
var task1 = function(callback){
tasksStatus.task1 = true;
callback();
};
Then you can check the global variable for which task is done and act accordingly.
Edit: a sample callback could be:
callback = function () {
var status = 0;
for(var s in tasksStatus) {
if(tasksStatus[s])
status += 33;
}
// update progress
if(status == 99) {
// done....
}
}

Related

How to wait for callback while iterating an array

I am working with a transnational framework within Javascript. So I need to wait for the previous query to finish before I move on. For example...
// Explicit this won't work because the length is not static
var i = [1,2,3]
doSomething(i[0], function(){
doSomething(i[1], function(){
doSomething(i[2], function(){
commitTransaction()
}
})
})
From this example I can't figure out a way to do this dynamically. It feels like a queue/recursion problem but I can't seem to crack it.
Does anyone else have an idea? I can also wrap in promises so that is an option as well, although that seems less synchronous.
Use async.eachSeries. So your code would translate to:
var transaction = {...};
async.eachSeries([1, 2, 3], function(value, callback) {
doSomething(value, transaction, callback);
}, function(err) {
if(err) throw err; // if there is any error in doSomething
commitTransaction(transaction);
});
jsFiddle Demo
I would suggest making a queue to do this. It would take the array, the generic callback function and a final function to callback with. Basically, the best way to accomplish this is to allow your functions to expect to have values injected.
The core assumption is that it is understood the caller will allow their callback function to have the current value and next callback function injected. That basically means we will end up with a function I have named queueAll which looks like this
function queueAll(arr,cbIteration,final){
var queue = [function(){ cbIteration(arr[arr.length-1],final) }];
for(var i = arr.length-2; i > 0; i--){
(function(next,i){
queue.unshift(function(){ cbIteration(arr[i],next) });
})(queue[0],i)
}
cbIteration(arr[0],queue[0]);
}
It takes the final call, places it in the queue, and then iterates, placing subsequent callback functions in the queue with the current value closed over, as well as closing over the front of the queue which at that point is the next call back. It is fairly simple to use. Pass it an array, a callback which expects values to be injected, and a final function.
In your case it would look like
queueAll(i,function(item,next){
doSomething(item,next);
},function(){
commitTransaction();
});
Stack Snippet Demo
//## <helper queue>
function queueAll(arr,cbIteration,final){
var queue = [function(){ cbIteration(arr[arr.length-1],final) }];
for(var i = arr.length-2; i > 0; i--){
(function(next,i){
queue.unshift(function(){ cbIteration(arr[i],next) });
})(queue[0],i)
}
cbIteration(arr[0],queue[0]);
}
//## </helper queue>
//## <user defined functions>
function doSomething(val,callback){
setTimeout(function(){
console.log(val);
callback();
},val*10);
}
function commitTransaction(){
console.log("commit");
}
//## </user defined functions>
//## <actual use>
var arr = [10,20,30];
queueAll(arr,function(item,next){
doSomething(item,next);
},function(){
commitTransaction();
});
//## </actual use>
Actually, I think promises are exactly what you're looking for. But for a traditional callback approach, consider the following:
var state = false,
doSomething = function (value, callback) {
/* do stuff with value */
if (!state)
doSomething(newValue, callback);
else
callback();
};

Nesting a Nested Function to Run in Sequence

I have three functions that I want to run in sequence (and then repeat, but I'm not even on that yet.) So when the first function displays its content and then leaves, the second function will play afterwards and do the same thing. Then that repeats into the third function. I'm using callbacks to try to achieve this.
This isn't a problem when I'm using only two functions, but when I introduce the third, It renders the first two menu boards, and then the third one comes afterwards, when they should render 1, 2 and then 3.
JavaScript for Reference
$(document).ready(function(){
Board1 = function(callback){
$('#menu-board .board.one .row').slideDown(800).delay(10000).slideUp(800, function(){
callback();
});
}
Board2 = function(callback){
$('#menu-board .board.two .row').slideDown(800).delay(10000).slideUp(800, function(){
callback();
});
}
Board3 = function(){
$('#menu-board .board.three .row').slideDown(800).delay(10000).slideUp(800);
}
Board1(Board2(Board3));
});
Any help is appreciated. Thank you.
Board1(Board2(Board3));
is equal to:
var res = Board2(Board3);
Board1(res);
So it won't act as you expect, it just start to execute Board2, and then start Board1, so Board3 is only guranteed to execute after Board2, while the order of Board1 is not relevant to Board2 and Board3.
You can use .bind to create a function that calls Board2 with give param Board3 like:
Board1(Board2.bind(null, Board3));
or just wrap them in another function:
Board1(function() {
Board2(Board3);
});
However, if you have too many functions to chain, use the methods above may not be a good idea, then you may create a chainer to do what you want:
// This function will accept a sequnce of functions in array, execute them in order, and call the done callback when all is complete.
var chain = function(sequences, done) {
// Manage the current index, and total items that would be called.
var idx = 0, length = sequences.length;
var caller = function() {
// When all functions in sequence is called, call final callback to notify user
// you may have to check if done is a function or not.
if (idx === length) {
if (typeof done === 'function') {
done();
}
return;
}
// Get the next function to call.
var currentTarget = sequences[idx];
// Pass caller to the target function, so when the function completes and call the callback
// the caller can takeover and start to call next function in sequence.
currentTarget(caller);
++idx;
};
caller();
};
// Create some test cases.
var sequence = [], i;
for (i = 0; i < 10; ++i) {
// Create some functions that will display some text after 1 sec when it get called.
sequence[i] = (function(index) {
return function(cb) {
setTimeout(function() {
var div = document.createElement('div');
div.innerHTML = 'Index is: ' + index;
document.body.appendChild(div);
cb();
}, 1000);
};
}(i));
}
// Demo.
chain(sequence, function() {
document.body.appendChild(document.createTextNode("All done."));
});
By the chain function above, you can now use it as chain([Board1, Board2, Board3]) and it keeps the codes simple even if you have a sequence of many functions.
PLUS:
From .slideUp()'s document:
Callback Function
If supplied, the callback is fired once the animation is complete.
This can be useful for stringing different animations together in
sequence. The callback is not sent any arguments, but this is set to
the DOM element being animated. If multiple elements are animated, it
is important to note that the callback is executed once per matched
element, not once for the animation as a whole.
As of jQuery 1.6, the .promise() method can be used in conjunction
with the deferred.done() method to execute a single callback for the
animation as a whole when all matching elements have completed their
animations ( See the example for .promise() ).
So if there's more than 1 element match to animate, the callback in your current function will get called more than once, you may have to rewrite your function with what the doc suggest to
Board1 = function(callback){
$('#menu-board .board.one .row').slideDown(800).delay(1000).slideUp(800).promise().done(callback);
}
You can see the jsfiddle that work as you expect.
why dont you just call the callback function directly in the slideup function.somewhat like this:
$('#menu-board .board.one .row').slideDown(800).delay(10000).slideUp(800, callback);
let me know if this does not work.
This is the reference for slideup function:
http://api.jquery.com/slideup/

Approach to check if callback was last fired?

I currently have a function which looks like that:
function update() {
buildUpdate(function(result) {
// send result to clients
});
}
This normally works correctly. However if I do something like:
// data state 1
update(); // this time, buildUpdate() won't take a long time
// do some work resulting in:
// data state 2
update(); // this time, buildUpdate() will take a long time
// and thus will finish after the third call
// do some work resulting in:
// data state 3
update(); // this time, buildUpdate() won't take a long time
As expected, the clients will receive three updates. However they are in the wrong order because the third call of update() did finish earlier than the second. From the clients point of view it looks like this:
Receives update calculated based on data state 1
Receives update calculated based on data state 3
Receives update calculated based on data state 2 (this update should not be sent)
Is there any design pattern or function which helps to avoid such a case?
Note: It doesn't matter if a client doesn't receive all updates. What matters is only that the last one received must be consistent with the current data state.
My idea was to generate on each invocation of update() a random ID. Afterwards I check in the callback whether its ID matches the last one that was generated. However the generation of the ID itself introduces a new async calculation and leads to much more code on each usage.
The easiest would probably be to add a callback
function update(callback) {
buildUpdate(function(result) {
// send result to clients
if (typeof callback == 'function') callback();
});
}
and do
update(function() { // when the first one finishes
update(function() { // run the second one
update(function() { // and when the second is finished, the third
update(); // and so on....
});
});
});
If you add the async middleware you would have more advanced methods available to deal with async behaviour.
My current approach works but is probably not the best solution.
Please submit an answer if you know a better way.
var outdated = function(f, cb) {
var counter = 0;
var finished = -1;
return function() {
var no = counter++;
a = [].slice.call(arguments);
a.unshift(function() {
if(no > finished) {
finished = no;
cb.apply(this, arguments);
}
});
f.apply(this, a);
};
};
Let's consider the following example:
var example = outdated(function(cb, a) {
setTimeout(function() {
cb(a);
}, a * 1000);
}, function(c) {
console.log('finished '+c);
});
example(1);
example(4);
example(2);
This will yield to the following output:
finished 1
finished 2
finished 4 is not being printed as it was called before finished 2 but ended after it.
To solve the actual problem as stated in the question, I would call the function like this:
var update = outdated(buildUpdate, function(result) {
// send update to clients
});
update();
// do some changes
update();

JavaScript's setInterval and when the function complete

I need to run a function on my node.js server, that completes the same task every 15 minutes.
I Used for that setInterval as in example number 3 here - http://tinyurl.com/c2jj7dl.
So, I got to something like this:
exports.start = function (list, callback){
setInterval(stuffTop.loadstuff, 900000, list, function (parsedList) {
// CODE STUFF HERE
// THEN THE CALLBACK.
callback(parsedDynamicList);
});
}
Actually this stuff work, but the function gets completed for the first time - only after 900000MS.
Is there an option to make to function complete (in the first round) - straight when called ? Thanks.
Use a function which recursivly calls itself:
foo = function(){
doStuff()
setTimeout(foo,900000)
}
In your case It would look like this:
exports.start = function (list, callback){
var foo = function () {
stuffTop.loadstuff(list, function(parsedList) {
//CODE STUFF HERE
//THEN THE CALLBACK
callback(parsedDynamicList);
setTimeout(foo,900000);
});
}
foo();
}
The solution to your question is simple. Call the function before going into the setInterval. Like this:
var callback=function(){}
var list=['some','list'];
var repeaterFunction = function(){console.log("do now!")}
var start = function (list, callback){
repeaterFunction();
var repeater = setInterval(repeaterFunction, 5000, list, function(parsedList){
// CODE STUFF HERE
// THEN THE CALLBACK.
callback(parsedDynamicList);
});
}
start()​
The fact that I use var repeater = setInterval(... allows for the clearInterval(repeater) whenever you wish.
Here's the fiddle

How do I store javascript functions in a queue for them to be executed eventually [duplicate]

This question already has answers here:
Semaphore-like queue in javascript?
(4 answers)
Closed 6 years ago.
I have created a Queue class in javascript and I would like to store functions as data in a queue. That way I can build up requests (function calls) and respond to them when I need to (actually executing the function).
Is there any way to store a function as data, somewhat similar to
.setTimeout("doSomething()", 1000);
except it would be
functionQueue.enqueue(doSomething());
Where it would store doSomething() as data so when I retrieve the data from the queue, the function would be executed.
I'm guessing I would have to have doSomething() in quotes -> "doSomething()" and some how make it call the function using a string, anyone know how that could be done?
All functions are actually variables, so it's actually pretty easy to store all your functions in array (by referencing them without the ()):
// Create your functions, in a variety of manners...
// (The second method is preferable, but I show the first for reference.)
function fun1() { alert("Message 1"); };
var fun2 = function() { alert("Message 2"); };
// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);
// Remove and execute the first function on the queue
(funqueue.shift())();
This becomes a bit more complex if you want to pass parameters to your functions, but once you've setup the framework for doing this once it becomes easy every time thereafter. Essentially what you're going to do is create a wrapper function which, when invoked, fires off a predefined function with a particular context and parameter set:
// Function wrapping code.
// fn - reference to function.
// context - what you want "this" to be.
// params - array of parameters to pass to function.
var wrapFunction = function(fn, context, params) {
return function() {
fn.apply(context, params);
};
}
Now that we've got a utility function for wrapping, let's see how it's used to create future invocations of functions:
// Create my function to be wrapped
var sayStuff = function(str) {
alert(str);
}
// Wrap the function. Make sure that the params are an array.
var fun1 = wrapFunction(sayStuff, this, ["Hello, world!"]);
var fun2 = wrapFunction(sayStuff, this, ["Goodbye, cruel world!"]);
// Create an array and append your functions to them
var funqueue = [];
funqueue.push(fun1);
funqueue.push(fun2);
// Remove and execute all items in the array
while (funqueue.length > 0) {
(funqueue.shift())();
}
This code could be improved by allowing the wrapper to either use an array or a series of arguments (but doing so would muddle up the example I'm trying to make).
Canonical answer posted here
Here is a nice Queue class you can use without the use of timeouts:
var Queue = (function(){
function Queue() {};
Queue.prototype.running = false;
Queue.prototype.queue = [];
Queue.prototype.add_function = function(callback) {
var _this = this;
//add callback to the queue
this.queue.push(function(){
var finished = callback();
if(typeof finished === "undefined" || finished) {
// if callback returns `false`, then you have to
// call `next` somewhere in the callback
_this.next();
}
});
if(!this.running) {
// if nothing is running, then start the engines!
this.next();
}
return this; // for chaining fun!
}
Queue.prototype.next = function(){
this.running = false;
//get the first element off the queue
var shift = this.queue.shift();
if(shift) {
this.running = true;
shift();
}
}
return Queue;
})();
It can be used like so:
var queue = new Queue;
queue.add_function(function(){
//start running something
});
queue.add_function(function(){
//start running something 2
});
queue.add_function(function(){
//start running something 3
});
Refer to the function you're storing without the () at the end. doSomething is a variable (that happens to be a function); doSomething() is an instruction to execute the function.
Later on, when you're using the queue, you'll want something like (functionQueue.pop())() -- that is, execute functionQueue.pop, and then execute the return value of that call to pop.
You can also use the .call() method of a function object.
function doSomething() {
alert('doSomething');
}
var funcs = new Array();
funcs['doSomething'] = doSomething;
funcs['doSomething'].call();
In addition, you can also add the function directly to the queue:
funcs['somethingElse'] = function() {
alert('somethingElse');
};
funcs['somethingElse'].call();

Categories

Resources