Can't seem to get JavaScript to run in synchronous - javascript

I have a few functions that need to be performed in order and JavaScript tends to do them asynchronous. I've looked into various methods of solving this problem including using callbacks, creating my own promise, a Promise.all() technique, and finally a newer version using async functions and await. I still wasn't able to get the code to run the way I wanted to.
The idea is, run initialize() first, initialize calls colorcells, and finally last thing to run is draw_path.
function initialize() {
for (let i = 1; i < 20; i++) {
setTimeout(() => {
colorcells(i)
}, i * 30)}
}
function colorcells (cell){
// then execute this function from initialize
}
function draw_path(){
// this should be the last function to get executed
}
async function init(){
await initialize()
draw_path()
}
// starts our code
init()

You could use promise, but it would make more sense to code a "queue" and when it is done, you call the next step.
const max = 20;
let current = 1;
function colorNext() {
colorCell(current);
current++;
if (current < max) {
window.setTimeout(colorNext, 30);
} else {
drawPath();
}
}
function colorCell(cell) {
console.log("Color", cell);
}
function drawPath() {
console.log('draw called');
}
colorNext();
It can be done with promises, but there is no need to read all those timeouts.

Related

Call next iteration after each callback

Lets say I've got the following code,
function someFunction(){
var i = 0;
while (i < 10){
someAsyncProcess(someField, function(err, data){
i++;
// i want the next iteration of the while loop to occur after this
}
}
}
The someAsyncProcess runs, and increments 'i'.
However, due to the async nature of JavaScript, the while loop runs thousands of times before i = 10. What if I want the while loop to run exactly 10 times. What if I want the while loop to execute the code inside only after the callback function has finished executing.
Is it possible to do this without a setTimeout function?
Please note that I am still relatively new to JavaScript so if I incorrectly used any jargon, correct me.
while is synchronous. You cannot make it wait until an asynchronous process is done. You cannot use a while loop in this case.
Instead you can put your code in a function and call the function itself again if the condition is met.
Example:
function someFunction() {
var i = 0;
function step() {
if (i < 10) {
someAsyncProcess(someField, function(err, data) {
i++;
step();
});
}
}
step();
}
There are quite a few libraries out there that provide ready-made solutions for this. You might also want to look into promises in general.
Use node package q which will help you return promises. You can achieve the same in the following manner using q.
var q = require('q');
function someFunction(){
var promises = []
var i = 0;
while (i < 10) {
promises.push(function() {
i++;
//write code here for using current value of i
})
}
return q.all(promises);
}
You can call someFunction() as below
someFunction().then(function(arrayOfResponseFromEachPromiseFunction) {
console.log(JSON.stringify(arrayOfResponseFromEachPromiseFunction, null, 4));
}).catch(function(err){
console.log(err);
}).done();
Please rectify if you find any syntax error. Hope it helps.
You need to use replace while loop Iteration with function recursion
function someFunction() {
var i = 0;
(function asyncWhile() {
if (i < 10) {
someAsyncProcess(someField, function(err, data) {
//You code here
i++;
asyncWhile();
});
}
})(); //auto invoke
}

How to know when async for loop is done?

I have a for loop that kicks off hundreds of async functions. Once all functions are done I need to run one last function but I can't seem to wrap my head around it knowing when all functions are complete.
I've tried promises but as soon as any of the functions in the loop resolve then my promise function completes.
for(var i = 0; i < someArray.length; i ++){
// these can take up to two seconds and have hundreds in the array
asyncFunction(someArray[i];
}
How can I tell once every function has completed?
An increment
You can add a callback which increments:
for (var i = 0; i < len; i++) {
asycFunction(someArray[i]);
asycFunction.done = function () {
if (i == someArray.length - 1) {
// Done with all stuff
}
};
}
A recursive approach
This type of approach is more liked by some developers but (might) take longer to execute because it waits for one to finish, to run another.
var limit = someArray.length, i = 0;
function do(i) {
asyncFunction(someArray[i]);
asyncFunction.done = function () [
if (i++ == someArray[i]) {
// All done!
} else { do(i); }
}
}
do(i++);
Promises
Promises aren't well supported at the moment but you can use a library. It will add a little bulk to your page for sure though.
A nice solution
(function (f,i) {
do(i++,f)
}(function (f,i) {
asyncFunction(someArray[i]);
asyncFunction.done = function () {
if (i++ === someArray.length - 1) {
// Done
} else { f(i) }
};
}, 0)
Many libraries have .all resolver:
jQuery
q
bluebird
and many more - https://promisesaplus.com/implementations
You can use them or learn their source code.
Assuming the code to be the body of function foo() :
function foo() {
return Promise.all(someArray.map(function(item) {
//other stuff here
return asyncFunction(item, /* other params here */);
}));
}
Or, if there's no other stuff to do, and no other params to pass :
function foo() {
return Promise.all(someArray.map(asyncFunction));
}
You can check number of response.
For every response you can increase counter value and if counter value same as someArray.length then you can assume all Async functions are done and can start next step.

Iterate over array running async task on each element

I have a list of items, which I want to run an async task on each.
I want to synchronize so each element will be processed once the preceding element has completed. What I've tried so far is:
function processItems(items) {
var i = 0;
while(i < items.length) {
asyncFunc(items[i], function() { i++ }); // asyncFunc takes a callback parameter
}
}
However this loops forever (I believe i is out of scope in the callback function).
Is there a better way to achieve this?
I think the following accomplishes what you're looking for:
function processItems(items) {
var i = 0,
length = items.length,
fn = function() {
if(i < length) {
asyncFunc(items[i], fn);
i++;
}
};
fn();
}
fn is a function that sets the callback equal to itself as long as the index is less than the length. Then I call fn once to start it off. Here's a fiddle:
http://jsfiddle.net/8A8CG/
Alternatively, if asyncFunc returns a promise, you can use Array#reduce to process the items in a series:
function processItems(items) {
return items.reduce((promise, item) => {
return promise.then(() => asyncFunc(item));
}, Promise.resolve());
}
If you need to execute a set of async function in series, I highly recommend the async module for node.
It offers a series method to execute async tasks in series. It also offers a waterfall method that will pass the results of the previous task to the next task.
Oops. You are looking for eachSeries. Here's how it might work for you:
var async = require('async');
async.eachSeries(items, asyncFunc, function(err){ if(err) return "OH NO"; return "Yay!"})
Make sure asyncFunc invokes a callback with either an error or null.

Should a function containing loop be async in NodeJS?

I am new to NodeJS and I am not really sure how should the following function be declared. The function contains only a for loop which generates a string. There are no "heavy-weight" calculations done.
Variant 1:
function getRandomString(arg) {
for (var i = 0; i < 100; i++) {
// ...
}
return string;
}
var randomString = getRandomString(arg);
// ... an async code which will use the string
Variant 2: Or should I make it async (async-style)? It would look something like this:
function getRandomString(arg, callback) {
for (var i = 0; i < 100; i++) {
// ...
}
callback(string);
}
getRandomString(arg, function(randomString) {
// Async code...
});
Or should I make it async? So something like this:
function getString(arg, callback) {
for(var i = 0;i<100;i++) {
// ...
}
callback(string);
}
No. That code does still run synchronousls, only with an odd callback style for returning the result. Since JS does no tail call optimisation or has continuation support, it just introduces the pyramid of doom without any benefit.
Do not use this unless you really make it asynchronous (setTimeout, nextTick etc), for example to defer the single loop iterations.
There is no benefit from making it "asynchronous". In fact, the code will run synchronously, with the getString method only exiting after the callback is complete.
The only decision you really have to make is one of coding style (Do you want it to seem asynchronous or not.)
function getString(arg, callback)
{
for(var i = 0;i<100;i++)
{
// ...
}
//Callback will execute synchronously, and you will wait here until it is complete
callback(string);
}

How can I create an Asynchronous function in Javascript?

Check out this code :
Link
<span>Moving</span>
$('#link').click(function () {
console.log("Enter");
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
});
console.log("Exit");
});
As you can see in the console, the "animate" function is asynchronous, and it "fork"s the flow of the event handler block code. In fact :
$('#link').click(function () {
console.log("Enter");
asyncFunct();
console.log("Exit");
});
function asyncFunct() {
console.log("finished");
}
follow the flow of the block code!
If I wish to create my function asyncFunct() { } with this behaviour, how can I do it with javascript/jquery? I think there is a strategy without the use of setTimeout()
​
You cannot make a truly custom asynchronous function. You'll eventually have to leverage on a technology provided natively, such as:
setInterval
setTimeout
requestAnimationFrame
XMLHttpRequest
WebSocket
Worker
Some HTML5 APIs such as the File API, Web Database API
Technologies that support onload
... many others
In fact, for the animation jQuery uses setInterval.
You can use a timer:
setTimeout( yourFn, 0 );
(where yourFn is a reference to your function)
or, with Lodash:
_.defer( yourFn );
Defers invoking the func until the current call stack has cleared. Any additional arguments are provided to func when it's invoked.
here you have simple solution (other write about it)
http://www.benlesh.com/2012/05/calling-javascript-function.html
And here you have above ready solution:
function async(your_function, callback) {
setTimeout(function() {
your_function();
if (callback) {callback();}
}, 0);
}
TEST 1 (may output '1 x 2 3' or '1 2 x 3' or '1 2 3 x'):
console.log(1);
async(function() {console.log('x')}, null);
console.log(2);
console.log(3);
TEST 2 (will always output 'x 1'):
async(function() {console.log('x');}, function() {console.log(1);});
This function is executed with timeout 0 - it will simulate asynchronous task
Here is a function that takes in another function and outputs a version that runs async.
var async = function (func) {
return function () {
var args = arguments;
setTimeout(function () {
func.apply(this, args);
}, 0);
};
};
It is used as a simple way to make an async function:
var anyncFunction = async(function (callback) {
doSomething();
callback();
});
This is different from #fider's answer because the function itself has its own structure (no callback added on, it's already in the function) and also because it creates a new function that can be used.
Edit: I totally misunderstood the question. In the browser, I would use setTimeout. If it was important that it ran in another thread, I would use Web Workers.
Late, but to show an easy solution using promises after their introduction in ES6, it handles asynchronous calls a lot easier:
You set the asynchronous code in a new promise:
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
Note to set resolve() when async call finishes.
Then you add the code that you want to run after async call finishes inside .then() of the promise:
asyncFunct.then((result) => {
console.log("Exit");
});
Here is a snippet of it:
$('#link').click(function () {
console.log("Enter");
var asyncFunct = new Promise(function(resolve, reject) {
$('#link').animate({ width: 200 }, 2000, function() {
console.log("finished");
resolve();
});
});
asyncFunct.then((result) => {
console.log("Exit");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Link
<span>Moving</span>
or JSFiddle
This page walks you through the basics of creating an async javascript function.
Since ES2017, asynchronous javacript functions are much easier to write. You should also read more on Promises.
If you want to use Parameters and regulate the maximum number of async functions you can use a simple async worker I've build:
var BackgroundWorker = function(maxTasks) {
this.maxTasks = maxTasks || 100;
this.runningTasks = 0;
this.taskQueue = [];
};
/* runs an async task */
BackgroundWorker.prototype.runTask = function(task, delay, params) {
var self = this;
if(self.runningTasks >= self.maxTasks) {
self.taskQueue.push({ task: task, delay: delay, params: params});
} else {
self.runningTasks += 1;
var runnable = function(params) {
try {
task(params);
} catch(err) {
console.log(err);
}
self.taskCompleted();
}
// this approach uses current standards:
setTimeout(runnable, delay, params);
}
}
BackgroundWorker.prototype.taskCompleted = function() {
this.runningTasks -= 1;
// are any tasks waiting in queue?
if(this.taskQueue.length > 0) {
// it seems so! let's run it x)
var taskInfo = this.taskQueue.splice(0, 1)[0];
this.runTask(taskInfo.task, taskInfo.delay, taskInfo.params);
}
}
You can use it like this:
var myFunction = function() {
...
}
var myFunctionB = function() {
...
}
var myParams = { name: "John" };
var bgworker = new BackgroundWorker();
bgworker.runTask(myFunction, 0, myParams);
bgworker.runTask(myFunctionB, 0, null);
Function.prototype.applyAsync = function(params, cb){
var function_context = this;
setTimeout(function(){
var val = function_context.apply(undefined, params);
if(cb) cb(val);
}, 0);
}
// usage
var double = function(n){return 2*n;};
var display = function(){console.log(arguments); return undefined;};
double.applyAsync([3], display);
Although not fundamentally different than the other solutions, I think my solution does a few additional nice things:
it allows for parameters to the functions
it passes the output of the function to the callback
it is added to Function.prototype allowing a nicer way to call it
Also, the similarity to the built-in function Function.prototype.apply seems appropriate to me.
Next to the great answer by #pimvdb, and just in case you where wondering, async.js does not offer truly asynchronous functions either. Here is a (very) stripped down version of the library's main method:
function asyncify(func) { // signature: func(array)
return function (array, callback) {
var result;
try {
result = func.apply(this, array);
} catch (e) {
return callback(e);
}
/* code ommited in case func returns a promise */
callback(null, result);
};
}
So the function protects from errors and gracefully hands it to the callback to handle, but the code is as synchronous as any other JS function.
Unfortunately, JavaScript doesn't provide an async functionality. It works only in a single one thread. But the most of the modern browsers provide Workers, that are second scripts which gets executed in background and can return a result.
So, I reached a solution I think it's useful to asynchronously run a function, which creates a worker for each async call.
The code below contains the function async to call in background.
Function.prototype.async = function(callback) {
let blob = new Blob([ "self.addEventListener('message', function(e) { self.postMessage({ result: (" + this + ").apply(null, e.data) }); }, false);" ], { type: "text/javascript" });
let worker = new Worker(window.URL.createObjectURL(blob));
worker.addEventListener("message", function(e) {
this(e.data.result);
}.bind(callback), false);
return function() {
this.postMessage(Array.from(arguments));
}.bind(worker);
};
This is an example for usage:
(function(x) {
for (let i = 0; i < 999999999; i++) {}
return x * 2;
}).async(function(result) {
alert(result);
})(10);
This executes a function which iterate a for with a huge number to take time as demonstration of asynchronicity, and then gets the double of the passed number.
The async method provides a function which calls the wanted function in background, and in that which is provided as parameter of async callbacks the return in its unique parameter.
So in the callback function I alert the result.
MDN has a good example on the use of setTimeout preserving "this".
Like the following:
function doSomething() {
// use 'this' to handle the selected element here
}
$(".someSelector").each(function() {
setTimeout(doSomething.bind(this), 0);
});

Categories