async-promise
Version:
Asynchronous coordination primitives for JavaScript and TypeScript
195 lines (194 loc) • 7.42 kB
JavaScript
var list_1 = require('./list');
var SCHEDULER_KIND = typeof setImmediate === "function" ? "setImmediate" :
typeof msSetImmediate === "function" ? "msSetImmediate" :
typeof MessageChannel === "function" ? "MessageChannel" :
typeof process === "object" && typeof process.nextTick === "function" ? "process.nextTick" :
typeof setTimeout === "function" ? "setTimeout" :
"unknown";
var Task = (function () {
function Task(onexecute, oncancel) {
if (typeof onexecute !== "function")
throw new TypeError();
this._onexecute = onexecute;
this._oncancel = oncancel;
}
Task.prototype.execute = function () {
var onexecute = this._onexecute;
this._onexecute = undefined;
this._oncancel = undefined;
if (onexecute != undefined) {
onexecute();
}
};
Task.prototype.cancel = function (reason) {
var oncancel = this._oncancel;
this._onexecute = undefined;
this._oncancel = undefined;
if (oncancel != undefined) {
oncancel(reason);
}
};
return Task;
})();
exports.Task = Task;
(function (TaskSchedulerPriority) {
TaskSchedulerPriority[TaskSchedulerPriority["none"] = -1] = "none";
TaskSchedulerPriority[TaskSchedulerPriority["background"] = 0] = "background";
TaskSchedulerPriority[TaskSchedulerPriority["send"] = 1] = "send";
})(exports.TaskSchedulerPriority || (exports.TaskSchedulerPriority = {}));
var TaskSchedulerPriority = exports.TaskSchedulerPriority;
var TaskScheduler = (function () {
function TaskScheduler() {
var _this = this;
this._backgroundQueue = new list_1.LinkedList();
this._sendQueue = new list_1.LinkedList();
this._marker = new list_1.LinkedListNode();
this._marked = false;
this._ontick = function () { return _this.tick(); };
if (SCHEDULER_KIND === "MessageChannel") {
this._channel = new MessageChannel();
this._channel.port2.onmessage = this._ontick;
}
}
Object.defineProperty(TaskScheduler, "default", {
get: function () {
return this._default || (this._default = new this());
},
enumerable: true,
configurable: true
});
Object.defineProperty(TaskScheduler.prototype, "max", {
get: function () {
if (this._sendQueue.size > 0) {
return TaskSchedulerPriority.send;
}
else if (this._backgroundQueue.size > 0) {
return TaskSchedulerPriority.background;
}
return TaskSchedulerPriority.none;
},
enumerable: true,
configurable: true
});
TaskScheduler.prototype.enqueue = function (priority, onexecute, oncancel) {
var _this = this;
this.requestTick();
var queue = this.getQueue(priority);
var node = new list_1.LinkedListNode(new Task(function () { return _this.onexecute(priority, node, onexecute); }, function (reason) { return _this.oncancel(priority, node, oncancel, reason); }));
queue.push(node);
return node.value;
};
TaskScheduler.prototype.delay = function (msec, onexecute, oncancel) {
var _this = this;
var handle;
var task = new Task(function () { return _this.ondelayexecute(handle, onexecute); }, function (reason) { return _this.ondelaycancel(handle, oncancel, reason); });
handle = setTimeout(function () { return task.execute(); });
return task;
};
TaskScheduler.prototype.requestTick = function () {
if (this._state !== "requested") {
this._state = "requested";
switch (SCHEDULER_KIND) {
case "setTimeout":
this._handle = setTimeout(this._ontick, 0);
break;
case "setImmediate":
this._handle = setImmediate(this._ontick);
break;
case "msSetImmediate":
this._handle = msSetImmediate(this._ontick);
break;
case "nextTick":
process.nextTick(this._ontick);
break;
case "postMessage":
this._channel.port1.postMessage();
break;
}
}
};
TaskScheduler.prototype.resetTick = function () {
if (this._state === "requested") {
this._state = "reset";
switch (SCHEDULER_KIND) {
case "setTimeout":
clearTimeout(this._handle);
break;
case "setImmediate":
clearImmediate(this._handle);
break;
case "msSetImmediate":
msClearImmediate(this._handle);
break;
}
this._handle = undefined;
}
};
TaskScheduler.prototype.tick = function () {
var state = this._state;
this._state = undefined;
this._handle = undefined;
if (state === "requested") {
if (!this._marked) {
this._backgroundQueue.push(this._marker);
this._marked = true;
}
var completed = false;
try {
var task = this.dequeue();
while (task) {
if (task === this._marker) {
this._marked = false;
break;
}
task.value.execute();
task = this.dequeue();
}
completed = true;
}
finally {
if (!completed) {
this.requestTick();
}
}
}
};
TaskScheduler.prototype.getQueue = function (priority) {
switch (priority) {
case TaskSchedulerPriority.background: return this._backgroundQueue;
case TaskSchedulerPriority.send: return this._sendQueue;
}
};
TaskScheduler.prototype.dequeue = function () {
return this._sendQueue.shift()
|| this._backgroundQueue.shift();
};
TaskScheduler.prototype.onexecute = function (priority, node, onexecute) {
var queue = this.getQueue(priority);
queue.delete(node);
if (onexecute != undefined) {
onexecute();
}
};
TaskScheduler.prototype.oncancel = function (priority, node, oncancel, reason) {
var queue = this.getQueue(priority);
queue.delete(node);
if (oncancel != undefined) {
oncancel(reason);
}
};
TaskScheduler.prototype.ondelayexecute = function (handle, onexecute) {
clearTimeout(handle);
if (onexecute != undefined) {
onexecute();
}
};
TaskScheduler.prototype.ondelaycancel = function (handle, oncancel, reason) {
clearTimeout(handle);
if (oncancel != undefined) {
oncancel(reason);
}
};
return TaskScheduler;
})();
exports.TaskScheduler = TaskScheduler;