How to create chain of asynchronous methods in node.js? - javascript

I want to create a chain of asynchronous methods in Node.js, for example:
function functionA(data, callback){
console.log("A")
// do something here
callback();
}
function functionB(data, callback){
console.log("B");
// do something here
callback();
}
function functionC(data, callback){
console.log("C");
// do something here
callback();
}
each function is independent, but when chained, they can be called orderly. For example:
functionA(data).functionC(data).functionB(data)
will print A then C then B. The chain's order can be re-arranged without restriction.
Here's what I have been searched:
Create chained methods in node.js?, --> here's the previous question regarding this very topic, very old, also not async
http://www.dustindiaz.com/async-method-queues/ --> depends on jquery, client side script, not node, not async
https://github.com/FuturesJS/FuturesJS/tree/v3 --> deprecated, the newer version (3) with chainify feature unfinished. Looks like an abandoned project
I use async a lot, I know about waterfall, series, and many functions that I use regularly, I just want to re-arrange it to something simpler to use in multiple places. I think about how to "chaining" them, so that in other file I can use the same method.
Here's my reason why async is not the answer that I expect.
Consider accounting problem, if there's a sell transaction with total $1200, first I had to put $1200 into asset:cash book(debit side), then I had to put $1200 into income book(credit side). Is it do-able with async? yes of course. it'll look like this:
async.series([
function(callback){
bookLibrary.debit('cash', 1200, callback);
},
function(callback){
bookLibrary.credit('income', 1200, callback);
}
]);
so I want to make it much simpler and easier to read by chaining them, like this:
bookLibrary.debit('cash', 1200).credit('income', 1200)

First off, to chain a bunch of functions, you need them to be configured as methods on a common object. Then, each method can return that object so the return result is the object and the next method can be called on that object.
So, to do something like this:
a().b().c();
You need a() to return an object that has the method b() on it as a property. And, similarly you need a().b() to return an object that has c() on it as a property. This is generally called the Fluent Interface. That's all pretty straightforward by itself for synchronous methods. This is exactly how jQuery does its chaining.
$(".foo").show().css("color", "blue");
All three of these calls all return a jQuery object and that jQuery object contains all the methods that you can chain.
In the example above, you could do synchronous chaining like this:
function a() {
}
a.prototype = {
b: function() {
// do something
return this;
},
c: function() {
// do something else
return this;
}
};
But, your question is about asynchronous operations. That is significantly more work because when you do:
a().b().c();
That's going to execute all three methods immediately one after the other and will not wait for any of them to complete. With this exact syntax, the only way I know of to support chaining is to build a queue where instead of actually executing .b(xxx) right away, the object queues that operation until a() finishes. This is how jQuery does animations as in:
$(".foo").slideUp().slideDown();
So, the object that is returned from each method can contain a queue and when one operation completes, the object then pulls the next item from the queue, assigns it's arguments (that are also held in the queue), executes it and monitors for that async operation to be done where it again pulls the next item from the queue.
Here's a general idea for a queue. As I got into this implementation, I realized that promises would make this a lot easier. Here's the general idea for an implementation that doesn't use promises (untested):
For simplicity of example for async operations, lets make a() execute a 10ms setTimeout, .b() a 50ms setTimeout and .c() a 100ms setTimeout. In practice, these could be any async operations that call a callback when done.
function a() {
if (!(this instanceof a)) {
return new a();
} else {
this.queue = [];
this.inProgress = false;
this.add(function(callback) {
// here our sample 10ms async operation
setTimeout(function() {
callback(null);
}, 10);
}, arguments);
}
}
a.prototype = {
b: function() {
this.add(function(callback) {
// here our sample 50ms async operation
setTimeout(function() {
callback(null);
}, 50);
return this;
}, arguments);
},
c: function(t) {
this.add(function(t, callback) {
// here our sample 100ms async operation
setTimeout(function() {
callback(null);
}, t);
return this;
}, arguments);
},
add: function(fn, args) {
// make copy of args
var savedArgs = Array.prototype.slice.call(args);
this.queue.push({fn: fn, args:savedArgs});
this._next();
},
_next: function() {
// execute the next item in the queue if one not already running
var item;
if (!this.inProgress && this.queue.length) {
this.inProgress = true;
item = this.queue.shift();
// add custom callback to end of args
item.args.push(function(err) {
this.inProgress = false;
if (err) {
// clear queue and stop execution on an error
this.queue = [];
} else {
// otherwise go to next queued operation
this._next();
}
});
try {
item.fn.apply(this, item.args);
} catch(e) {
// stop on error
this.queue = [];
this.inProgress = false;
}
}
}
};
// usage
a().b().c(100);
If we use promises for both our async operations and for the queuing, then things get a bit simpler:
All async operations such as firstAsyncOperation and secondAsyncOperation here return a promise which drastically simplifies things. The async chaining is done for us by the promise infrastructure.
function a(arg1, arg2) {
if (!(this instanceof a)) {
return new a(arg1, arg2);
} else {
this.p = firstAsyncOperation(arg1, arg2);
}
}
a.prototype = {
b: function() {
return this._chain(secondAsyncOperation, arguments);
},
c: function() {
return this._chain(thirdAsyncOperation, arguments);
},
_chain: function(fn, args) {
var savedArgs = Array.prototype.slice.call(args);
this.p = this.p.then(function() {
return fn.apply(this, savedArgs);
});
return this;
},
then: function(a, b) {
this.p = this.p.then(a, b);
return this;
},
catch: function(fn) {
this.p = this.p.catch(fn);
return this;
}
};
// usage:
a().b().c(100).then(function() {
// done here
}).catch(function() {
// error here
});

You can use async waterfall to do that, this should meet your requirement.
async.waterfall([
function(callback) {
callback(null, 'one', 'two');
},
function(arg1, arg2, callback) {
// arg1 now equals 'one' and arg2 now equals 'two'
callback(null, 'three');
},
function(arg1, callback) {
// arg1 now equals 'three'
callback(null, 'done');
}
], function (err, result) {
// result now equals 'done'
});

You can do this by having all your functions enclosed in a single object , just like below.
var Ext = {
function a() {
return this;
}
function b() {
return this;
}
}
then you can call them as below
Ext.a().b();
for detailed example please look at the code of my javascript library which does exactly what you need https://github.com/waqaskhan540/MapperJs

Related

Async transactions in javascript

First of all rollback is something that I do not care about.
I would like to be able to lock a sequence of async functions/promises/tasks (let's call it a "transaction") with a name/id (or array of names), so that they happen in sequence, and so that any other "transaction" with the same name(s) that are run by another part of the system are delayed from starting until the running transaction using the same name(s) has completed. So it basically is queueing the sequences of async tasks, or "transaction"s.
Here is some example code of the situation:
function a()
{
// do stuff
return new Promise(/*...*/);
}
function b()
{
// do stuff
return new Promise(/*...*/);
}
function c()
{
// do stuff
return a.then(() => b());
}
Now at any time the system could call a, b, or c, and when it does I don't want c and b running at the same time, but obvious c depends on b.
I've been looking for a package on npm to help with this but I haven't found anything, I wonder if anyone can suggest something that I might have missed that would help with this?
I think gulp tasks can help you out of the box. This guarantees that c always run after b and so b after a
const gulp = require('gulp');
gulp.task('a', done => {
// do stuff
console.log('a');
done();
});
gulp.task('b', ['a'], done => {
// do stuff
console.log('b');
done();
});
gulp.task('c', ['b'], done => {
// do more stuff
console.log('c');
done();
});
gulp.start('c'); // Logs a, b, c
Try it!
You could write your own little transaction manager.
const transactions = {};
function doTransaction(name, promiseFunc) {
transactions[name] = (transactions[name] || Promise.resolve()).then(promiseFunc);
}
Use async/await and have babel transpile it. Async Babel Docs
function a()
{
// do stuff
return new Promise(/*...*/);
}
async function b()
{
const aData = await a();
// do stuff
return new Promise(/*...*/);
}
async function c()
{
const bData = await b();
// do stuff
return bData;
}
You can go for https://github.com/Reactive-Extensions/RxJS
They have many functions to handle single/multiple/dependent/parallel async calls.
function a()
{
// do stuff
return new Promise(/*...*/);
}
function b()
{
// do stuff
return new Promise(/*...*/);
}
function c()
{
// do stuff
return new Value;
}
a().then(function(data_a) {
// you can make use of return value (which is data_a) here or as an argument for function b or even function c
b().then(function(data_b) {
// you can make use of return value (which is data_b) here or as an argument for function c
c().then(function(data_c) {
// do your coding here
});
});
});
you can check this link for reference : https://spring.io/understanding/javascript-promises
Ok, here's my take.
You use a wrapper for your function b which returns and object with 2 methods: doCall and wait. The wrapper should be called only once.
doCall will call your function and trace its completion for the wait() function.
wait() will wait for the completion and always resolve when doCall() finishes
Now for the code, also on CodePen (see developer console):
function wrapPromiseFn(fn) {
var prev = null;
var doCall = function() {
var retValue;
prev = new Promise(function(resolve, reject) {
retValue = fn();
retValue.then(function(result) {
resolve(true);
});
retValue.catch(function(result) {
resolve(true);
});
});
return retValue;
};
var wait = function() {
return prev ? prev : Promise.resolve(false);
};
return {
doCall: doCall,
wait: wait
};
}
function a() {
return Promise.resolve(42);
}
function b() {
//return Promise.reject(new Date());
return Promise.resolve(new Date().getTime());
}
var wrappedB = wrapPromiseFn(b);
function doStuff() {
return wrappedB.wait().then(function(didWait) {
return a().then(function(_a) {
return wrappedB.doCall().then(function(_b) {
console.log("didWait, a, b: ", didWait, _a, _b);
});
});
});
}
//run it twice to prove it did wait
doStuff().then(doStuff)
It proves the concept, of course it would need some polish to pass arguments from doCall to the wrapped function.

chaining async method calls - javascript

You have a prototype object Foo with two async method calls, bar and baz.
var bob = new Foo()
Foo.prototype.bar = function land(callback) {
setTimeout(function() {
callback()
console.log('bar');
}, 3000);
};
Foo.prototype.baz = function land(callback) {
setTimeout(function() {
callback()
console.log('baz');
}, 3000);
};
We want to do bob.bar().baz() and have it log "bar" and "baz" sequentially.
If you cannot modify the method calls (including passing in your callback function), how can you pass a default callback into these method calls?
Some ideas:
Wrap "bob" with decorator (still fuzzy on how to implement, could use a small example)
Modify constructor to assign default callback if none assigned (have not considered if this is possible or not)
Use a generator wrapper that will continue to call next method until none are left?
The more recommended way instead is to use promises as this is the community-wide practice to do async work.
We want to do bob.bar().baz() and have it log "bar" and "baz"
sequentially.
Why would you want to do that just to achieve this bob.bar().baz() "syntax"? You could do it pretty neatly using the Promise API w/o additional efforts to make that syntax work that indeed increases code complexity reducing the actual readability.
So, you might want to consider using the promise-based approach like this. It offers much flexibility than what you would have achieved with your approach:
Foo.prototype.bar = function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve()
console.log('bar');
}, 3000);
};
};
Foo.prototype.baz = function () {
return new Promise(function (resolve) {
setTimeout(function () {
resolve()
console.log('baz');
}, 3000);
};
};
Now you'd do this to run them sequentially one after another:
var bob = new Foo();
bob.bar().then(function() {
return bob.baz();
});
// If you're using ES2015+ you could even do:
bob.bar().then(() => bob.baz());
If you need to chain more functions you could simply do it:
bob.bar()
.then(() => bob.baz())
.then(() => bob.anotherBaz())
.then(() => bob.somethingElse());
Anyway, if you're not used to using promises you might want to read this
Warning this isn't quite right yet. Ideally we'd subclass Promise and have proper then/catch functionality but there are some caveats with subclassing bluebird Promise. The idea is to store an internal array of promise generating functions, then when a Promise is waited on (then/await) serially wait on those promises.
const Promise = require('bluebird');
class Foo {
constructor() {
this.queue = [];
}
// promise generating function simply returns called pGen
pFunc(i,pGen) {
return pGen();
}
bar() {
const _bar = () => {
return new Promise( (resolve,reject) => {
setTimeout( () => {
console.log('bar',Date.now());
resolve();
},Math.random()*1000);
})
}
this.queue.push(_bar);
return this;
}
baz() {
const _baz = () => {
return new Promise( (resolve,reject) => {
setTimeout( () => {
console.log('baz',Date.now());
resolve();
},Math.random()*1000);
})
}
this.queue.push(_baz);
return this;
}
then(func) {
return Promise.reduce(this.queue, this.pFunc, 0).then(func);
}
}
const foo = new Foo();
foo.bar().baz().then( () => {
console.log('done')
})
result:
messel#messels-MBP:~/Desktop/Dropbox/code/js/async-chain$ node index.js
bar 1492082650917
baz 1492082651511
done
If you want to avoid callback hell and keep your sanity ES6 promises are the most appropriate approach for the sake of functional programming. You just chain up your sequential asynchronous tasks in the asynchronous timeline just like working in a synchronous timeline.
In this particular case you just need to promisify your asynchronous functions. Assume that your asynch functions takes a data and a callback like asynch(data,myCallback). Let us assume that the callback is error first type.
Such as;
var myCallback = (error,result) => error ? doErrorAction(error)
: doNormalAction(result)
When your asynch function is promisified, you will actually be returned a function which takes your data and returns a promise. You are expected to apply myCallback at the then stage. The return value of myCallback will then be passed to the next stage at where you can invoke another asynch function supplied with the return value of myCallback and this goes on and on as long as you need. So let's see how we shall implement this abstract to your workflow.
function Foo(){}
function promisify(fun){
return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
}
function myCallback(val) {
console.log("hey..! i've got this:",val);
return val;
}
var bob = new Foo();
Foo.prototype.bar = function land(value, callback) {
setTimeout(function() {
callback(false,value*2); // no error returned but value doubled and supplied to callback
console.log('bar');
}, 1000);
};
Foo.prototype.baz = function land(value, callback) {
setTimeout(function() {
callback(false,value*2); // no error returned but value doubled and supplied to callback
console.log('baz');
}, 1000);
};
Foo.prototype.bar = promisify(Foo.prototype.bar);
Foo.prototype.baz = promisify(Foo.prototype.baz);
bob.bar(1)
.then(myCallback)
.then(bob.baz)
.then(myCallback)

Promise loops (bluebird) - wrap object in async

I have a question about promises.
I am using Bluebird Promise library and build a small async library with it.
I am trying to waterfall promises with the use of a function.
Say I use promises like so:
Promise.resolve()
.then(function () {
console.log("called 1")
return 1;
}).then(function () {
return new Promise (function (res, rej) {
setTimeout(function () {
console.log("called 2")
res(2);
}, 1500);
});
}).then(function () {
console.log("called 3")
return 3;
});
This does in fact wait in a loop and return 1,2,3 in order.
How do I wrap it into a function so that I can do something like this:
a();b();c();, or a().b().c(); where a() puts something onto a chain, b() puts something onto a chain, and c() puts something onto a chain in order.
Since then() returns a new promise, it can all go out of order, so something like
does not work:
var promise = Promise.resolve();
function a () {
promise.then(function () {
// do sync/async
});
}
function b () {
promise.then(function () {
//do sync/async
});
}
function c ...
Thank you for your time :]
I'm not sure what the goal is here. Do you want to have an arbitrary number of things run in sequence where the sequence is known in advance? Or is this a case where the sequence is discovered as you go? The NodeJS streams interface is a lot better for processing an unknown number of things sequentially (#tadman)
Sequence is discoverable, goal is to have ability to call a().b().c() or b().a().d(). Async library on a client-side.
Update: If I do as #zerkms says it does not work as expected. My bad, should work ok, but with lack of context/code did not give me enough info to expand on. Still thank you for your answer, as it gave me more food for thought.
Update: See my answer
You could use a scoped prototype and just add those methods there
Promise.prototype.a = function() {
return this.then(function() {
console.log("called 1")
return 1;
});
};
Promise.prototype.b = function() {
return this.delay(1500).then(function() {
console.log("called 2")
return 1;
});
};
Promise.prototype.c = function() {
return this.then(function() {
console.log("called 3")
return 3;
});
};
I use this to create neat DSLs e.g. with git:
https://gist.github.com/petkaantonov/6a73bd1a35d471ddc586
Thanks to #tadman I came up with this so far, seems to work as I expect it to.
The problem was that I did not update the promise before calling then on it, and it was branching instead of calling it in sequence.
And this is what I wanted - to turn an object that has both sync/async into async to allow chaining. Petka (#Esailija) also shows great example of building DSLs above (semvar version bumping & git pushing) by extending bluebird library, but for my purposes this is enough.
var Sample = function () {
this.promise = Promise.resolve();
};
Sample.prototype.a = function () {
this.then(function () {
console.log("1");
});
return this;
};
Sample.prototype.b = function () {
this.then(function () {
return new Promise(function (res, rej) {
setTimeout(function() {
console.log("2");
res();
}, 500);
});
});
return this;
};
Sample.prototype.c = function () {
this.then(function () {
console.log("3");
})
return this;
};
Sample.prototype.chainPromise = function (func) {
this.promise = this.promise.then(func);
};
var s = new Sample();
s.a().b().c();
or even then instead of chainPromise?
Sample.prototype.then = function (func) {
this.promise = this.promise.then(func);
return this.promise;
};

Javascript Proper Class constructor

I am trying to create a class that in its constructor uses some helper functions. Is there a way to move these helpers to the prototype? The problem is that the constructor does some asynchronous calls to the database and I need to apps in a callback function so I can continue execution after the data was retrieved.
I want to move stuff to the prototype, because if I understood correctly, these functions are not tied to a single object, so if I have multiple objects they will still call the same code but with different context.
Class = function(id, callback) {
var that = this,
addCore = function(err, model) {
that.id = model._id
that.core = model
callback(err, that)
},
addTopology = function() {
}
if (arguments.length === 2) {
gameOps.findById(id, addCore)
} else {
callback = id
gameOps.create(addCore)
}
}
Class.prototype = {
addPlayer: function(player, callback) {
gameOps.addPlayer(player, this.model, callback)
}
}
I want to move stuff to the prototype, because if I understood correctly, these functions are not tied to a single object, so if I have multiple objects they will still call the same code but with different context.
Yes. However, that is not what you want: The asynchronous callbacks need to be tied on specific instances.
If you don't want to have too much stuff floating around your constructor, you might reconsider your design:
function Class(model) {
this.id = model._id;
this.core = model;
}
Class.prototype.addPlayer = function(player, callback) {
gameOps.addPlayer(player, this.model, callback);
};
Class.fromDatabase = function(id, callback) {
function addCore(err, model) {
if (err)
callback(err);
else
callback(null, new Class(model))
}
function addTopology() {
}
if (arguments.length === 2) {
gameOps.findById(id, addCore)
} else {
callback = id
gameOps.create(addCore)
}
}

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