Objective
Few days back I had a small requirement of running set of javascript method asynchronously. Kind of how ThreadPool works in C# or Java. So objective was to provide set methods with there required parameters and some jquery plug-in will take care of it's calling and finally after the execution callback method (provided during assignment) should fire back.
Introduction
Sometime it could be very useful, specially when you have set of javascript method, which can be fired and forget.
Background
Implemented code is very simple and easy to follow. It will be nice if read has knowledge of javascript/jquery knowledge.
Using the code
So to achieve this lets divide the whole objective into two parts.
- Jquery plug-in which will have gateway method to process user methods async.
- Consume jquery plug-in and pass set of methods into that
Lets see how jquery plug-in looks like:
jQuery.extend({
JobPool: function (options, job, callback, data) {
var obj = this;
var options = $.extend({
}, options);
var joblist = Array();
var QueueJob = function (job, callback, ops, data) {
if (job == 'undefined') {
return;
}
ops = ops || {};
var jobItem = new JobItem(job, callback, ops, data);
if (jobItem) {
joblist.push(jobItem);
QueueChanged.call();
}
};
var JobItem = function (job, callback, ops, data) {
var jobitem = this;
ops = ops || {};
this.Data = data;
this.Job = job;
this.Callback = callback;
this.Run = function () {
try {
if (!jobitem.Job) return;
var returnValue = jobitem.Job(jobitem.Data);
jobitem.Callback(returnValue);
}
catch (e) { }
}
}
var AjaxCall = function (jobItem) {
if (!jobItem) jobItem = this;
$.ajax({
url: "#",
type: 'GET',
dataType: 'html',
async: true,
timeout: 3000,
cache: false,
data: '',
success: function (dt, x) {
if (typeof(jobItem.Run) == 'function')
jobItem.Run.call();
QueueChanged.call();
},
error: function (obj, x) {
if (typeof(jobItem.Run) == 'function')
jobItem.Run.call();
QueueChanged.call();
}
});
};
var QueueChanged = function () {
if (joblist == null || joblist.length == 0) return;
var jobitem = joblist.pop();
AjaxCall.call(jobitem);
}
QueueJob(job, callback, options, data);
return this;
}
});
AjaxCall is the helper method which actually simulate async nature. I am using $.ajax helper method to simulate async nature, because in javascript we don't have any API to support async nature. Thanks to HTML5, at least we have new Worker api.
JobItem is the container which keep actual method to call and QueueJob is queuing the job to an array and since we have change in the array, so we are calling QueueChanged api to process JobItem from updated Queue list.
Now lets see how we can consume it in our code.
$(function () {
for (i = 0; i < 10; i++) {
$.JobPool({}, AddEntry, callbackItem, { 'value': "In call 1-"+i });
}
AddEntry("After Call");
});<span style="font-size: 14px;"> </span>
Lets we are going to call some method when our document loaded. AddEntry is the method we are calling in Async way. Once AddEntry is processed we will be getting callback and our callbackItem method will be fired with return value. Last section of our JobPool method is the Json data which will be passed as input AddEntry method.
Now lets follow our callback method. callbackItem method will be fired once AddEntry method finished it's job.
function callbackItem(obj) {
AddEntry("got callback-");
}
Lets see our sample AddEntry method, which should be replaced with your actual javascript method.
function AddEntry(obj) {
var strVal = '';
if (typeof (obj) == 'object')
strVal = obj.value;
else
strVal = obj;
var el = document.createElement("div");
$(el).text(strVal + " - " + new Date().getTime().toString());
$('#container')[0].appendChild(el);
}
This AddEntry method is just sample method. In this place you can use any method which will be called in Async way. In your html page you should have one <div> whose id is container.
If you run the above example you will notice we are calling methods (AddEntry) in a sequential way, but when actual method is being called are not in sequence. If you keep on press F5 you will see different outcome time to time. So it will be unpredictable sometime when which method will be fired. Very similar to ThreadPool.
Points of Interest
We all know it's simple but in my opinion it's really fun. Though I drawn similarity with ThreadPool, but please don't read me wrong. ThreadPool is not this much simple. There are many improvement can be done in this code. Firstly try .. catch
is not applied in all the places, which I should add. Secondly all the method is consider for action as soon as that method added to the list. It's not right thing. I should check how many operations alive and arrange next method call based on that. Otherwise if many javascript method is called at same time, UI thread will be blocked and user might be frustrated by seeing it.
I am sure missed lot of points here, so your suggestions are well accepted and lets learn together. Your suggestions will encourage me in writing more cool! stuffs.
That's all folks!
<embed type="application/x-dap-background" id="DAPPlugin" style="visibility: collapse;" />