The problem of long running javascript tasks has been covered by Julien Lecomte, and Ajaxian. However, I wanted a way to classify this functionality using prototype. I found this post by eternal, which is close to what I wanted but still not quite. So I took it and modified it the way I did want. Basically, you include the following code (requires the prototype library to work):
var Task = Class.create({
timeout: null,
options: null,
working: false,
workStartTime: NaN,
initialize: function(options) {
this.options = Object.extend({
autoStart: true,
workMaxTime: 100,
timeout: 0,
onProgress: null,
onComplete: null,
onError: null
}, options || {});
if(this.options.autoStart) {
this.start();
}
},
start: function() {
if(this.working) return;
this.working = true;
this._doWork();
},
stop: function() {
if(!this.working) return;
clearTimeout(this.timeout);
this.working = false;
},
toggle: function() {
if(this.working) {
this.stop();
} else {
this.start();
}
},
_checkTime: function() {
if (new Date().getTime() - this.workStartTime
> this.options.workMaxTime) {
return false;
} else {
return true;
}
},
_doWork: function() {
this.workStartTime = new Date().getTime();
try {
result = this._work();
if(result) {
if(this.options.onProgress) {
if (typeof(result) == "number") {
if (0 > result) result = 0;
else if (100 < result) result = 100;
} else {
result = NaN;
}
try{this.options.onProgress(result)}catch(e){};
}
this.timeout = setTimeout(this._doWork.bind(this),
this.options.timeout);
} else {
this.working = false;
if(this.options.onComplete) {
try{this.options.onComplete()}catch(e){};
}
}
} catch (e) {
this.working = false;
if(this.options.onError) {
try{this.options.onError(e)}catch(e){};
}
}
},
_work: function() {
return false;
//
// This is the method that you need to override to make your task
// work properly, and it should look something like the following:
//
// while (there is work to do) {
// do some work...
// if (!this._checkTime()) {
// return true or a number > 0 and <= 100 to signify that
// more work needs to be done
// }
// }
// return false;
//
}
});
and then you use it like so:
function onProgress(progress) {
var divProgress = $("divProgress");
divProgress.innerHTML = "" + progress + "%";
}
function onComplete() {
$("divComplete").innerHTML = "complete";
}
var MyTask = Class.create(Task, {
currNumber: 0,
maxNumber: 50000,
_work: function() {
while (this.currNumber <= this.maxNumber) {
$("divNumber").innerHTML = this.currNumber++;
if (!this._checkTime())
return 100.0*this.currNumber/this.maxNumber;
}
return false;
}
});
var myTask = new MyTask(
{onProgress:onProgress, onComplete:onComplete}
);
An example of this working can be found here.
Tags: javascript