welsonjs/lib/task.js
2022-09-22 17:02:41 +09:00

229 lines
6.4 KiB
JavaScript

//////////////////////////////////////////////////////////////////////////////////
// Task API (Time-sharing based `async`, `setTimeout`, `setInterval`, implementation in WSH.js)
/////////////////////////////////////////////////////////////////////////////////
/* // example:
* // var TASK = require("lib/task");
* // var taskQueue = TASK.createTaskQueue();
* // TASK.putTask(queue, TASK.createTask(function(task, a, b, c) { console.log(a + b + c); sleep(100); }, [1, 2, 3]))
* // .then(TASK.createTask(function(task, a, b, c) { console.log(a + b + c); sleep(200); }, [4, 5, 6]))
* // .then(TASK.createTask(function(task, a, b, c) { console.log(a + b + c); sleep(300); }, [7, 8, 9]))
* // ;
* // TASK.putTask(queue, TASK.createTask(function(task, a, b, c) { console.log(a + b + c); sleep(100); }, [3, 2, 1])
* // .then(TASK.createTask(function(task, a, b, c) { console.log(a + b + c); sleep(200); }, [6, 5, 4]))
* // .then(TASK.createTask(function(task, a, b, c) { TASK.stop(); console.log(a + b + c); sleep(300); }, [9, 8, 7]))
* // ;
* // taskQueue.run();
*/
function Task(f, params) {
this.f = f;
this.params = params;
this.nextTask = null;
this.failTask = null;
this.when = 0;
this.delay = 0;
this.callCount = 0;
this.setNextTask = function(task) {
this.nextTask = task;
return this;
};
this.setFailTask = function(task) {
this.failTask = task;
return this;
};
this.setWhen = function(when) {
this.when = when;
return this;
};
this.setDelay = function(delay) {
this.delay = delay;
return this;
};
this.upCallCount = function() {
this.callCount++;
return this;
};
this.resetCount = function() {
this.callCount = 0;
return this;
};
}
function TaskQueue() {
this._task = null;
this._keepalive = true;
this.queue = [];
this.put = function(task, delay) {
var now = new Date();
try {
task.setWhen(now.getTime());
if (typeof(delay) !== "undefined") {
task.setDelay(delay);
}
this._task = task;
this.queue.push(task);
} catch(e) {
console.error("TaskQueue.put exception: " + e.message);
}
return this;
};
this.get = function() {
var task = null;
var now = new Date();
try {
if (this.queue.length > 0) {
var delta = this.queue.map(function(task) {
return task.when + task.delay - now.getTime();
});
var i = delta.indexOf(Math.min.apply(Math, delta));
var d = this.queue[i].when + this.queue[i].delay - now.getTime();
if (i > -1 && d <= 0) {
console.log("Task", i, d);
task = this.queue.splice(i, 1)[0];
}
}
} catch(e) {
console.error("TaskQueue.get: " + e.message);
}
return task;
};
this.next = function() {
var result = null;
try {
var task = this.get();
if (task != null) {
try {
result = task.f.apply(Task, [task].concat(task.params));
if (task.nextTask != null) {
this.put(task.nextTask, task.nextTask.delay);
}
task.upCallCount(); // 호출 횟수 기록
} catch (e) {
console.error("Task exception: " + e.message);
console.error("task.f: " + typeof(task.f));
console.error("task.params: " + typeof(task.params));
// 태스크 개별 오류 처리
if (task.failTask) {
this.put(task.failTask, 0);
}
}
}
} catch(e) {
console.error("TaskQueue.next: " + e.message);
}
return result;
};
this.then = function(task, delay) {
try {
if (typeof(delay) !== "undefined") {
task.setDelay(delay);
}
this._task.setNextTask(task);
this._task = task;
return this;
} catch(e) {
console.error("TaskQueue.then: " + e.message);
console.error(this._task);
}
};
this.run = function() {
this._keepalive = true;
while(this._keepalive) {
this.next();
sleep(1);
}
};
this.stop = function() {
this._keepalive = false;
};
}
function createTaskQueue() {
return new TaskQueue();
}
function createTask(f, params, failTask) {
try {
return (new Task(f, params)).setFailTask(failTask);
} catch(e) {
console.error("createTask exception: " + e.message);
}
}
function putTask(q, task, delay) {
try {
if (q instanceof TaskQueue && task instanceof Task) {
return q.put(task, delay);
}
} catch(e) {
console.error("putTask exception: " + e.message);
}
}
function nextTask(q) {
try {
return q.next();
} catch(e) {
console.error("nextTask exception: " + e.message);
}
}
function run(q) {
q.run();
}
function stop(q) {
q.stop();
}
////////////////////////////////////////////////////
// START Global functions
////////////////////////////////////////////////////
var __taskQueue__ = new TaskQueue();
function setTimeout(f, delay) {
var params = (arguments.length > 2 ? arguments.slice(2) : []);
var task = new Task(f, delay);
__taskQueue__.put(task);
}
// TODO: compatiblity with clearInterval()
function setInterval(f, delay) {
var params = (arguments.length > 2 ? arguments.slice(2) : []);
var task = new Task(f, delay);
task.setNextTask(task);
__taskQueue__.put(task);
}
exports.__taskQueue__ = __taskQueue__;
exports.setTimeout = setTimeout;
exports.setInterval = setInterval;
////////////////////////////////////////////////////
// END Global functions
////////////////////////////////////////////////////
exports.Task = Task;
exports.TaskQueue = TaskQueue;
exports.createTaskQueue = createTaskQueue;
exports.createTask = createTask;
exports.putTask = putTask;
exports.nextTask = nextTask;
exports.run = run;
exports.stop = stop;
exports.VERSIONINFO = "Task Module (task.js) version 0.2.2";
exports.global = global;
exports.require = require;