139 lines
3.7 KiB
JavaScript
139 lines
3.7 KiB
JavaScript
"use strict";
|
|
|
|
var utils = require("./utils");
|
|
|
|
module.exports = function batchProcessorMaker(options) {
|
|
options = options || {};
|
|
var reporter = options.reporter;
|
|
var asyncProcess = utils.getOption(options, "async", true);
|
|
var autoProcess = utils.getOption(options, "auto", true);
|
|
|
|
if(autoProcess && !asyncProcess) {
|
|
reporter && reporter.warn("Invalid options combination. auto=true and async=false is invalid. Setting async=true.");
|
|
asyncProcess = true;
|
|
}
|
|
|
|
var batch = Batch();
|
|
var asyncFrameHandler;
|
|
var isProcessing = false;
|
|
|
|
function addFunction(level, fn) {
|
|
if(!isProcessing && autoProcess && asyncProcess && batch.size() === 0) {
|
|
// Since this is async, it is guaranteed to be executed after that the fn is added to the batch.
|
|
// This needs to be done before, since we're checking the size of the batch to be 0.
|
|
processBatchAsync();
|
|
}
|
|
|
|
batch.add(level, fn);
|
|
}
|
|
|
|
function processBatch() {
|
|
// Save the current batch, and create a new batch so that incoming functions are not added into the currently processing batch.
|
|
// Continue processing until the top-level batch is empty (functions may be added to the new batch while processing, and so on).
|
|
isProcessing = true;
|
|
while (batch.size()) {
|
|
var processingBatch = batch;
|
|
batch = Batch();
|
|
processingBatch.process();
|
|
}
|
|
isProcessing = false;
|
|
}
|
|
|
|
function forceProcessBatch(localAsyncProcess) {
|
|
if (isProcessing) {
|
|
return;
|
|
}
|
|
|
|
if(localAsyncProcess === undefined) {
|
|
localAsyncProcess = asyncProcess;
|
|
}
|
|
|
|
if(asyncFrameHandler) {
|
|
cancelFrame(asyncFrameHandler);
|
|
asyncFrameHandler = null;
|
|
}
|
|
|
|
if(localAsyncProcess) {
|
|
processBatchAsync();
|
|
} else {
|
|
processBatch();
|
|
}
|
|
}
|
|
|
|
function processBatchAsync() {
|
|
asyncFrameHandler = requestFrame(processBatch);
|
|
}
|
|
|
|
function clearBatch() {
|
|
batch = {};
|
|
batchSize = 0;
|
|
topLevel = 0;
|
|
bottomLevel = 0;
|
|
}
|
|
|
|
function cancelFrame(listener) {
|
|
// var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.clearTimeout;
|
|
var cancel = clearTimeout;
|
|
return cancel(listener);
|
|
}
|
|
|
|
function requestFrame(callback) {
|
|
// var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function(fn) { return window.setTimeout(fn, 20); };
|
|
var raf = function(fn) { return setTimeout(fn, 0); };
|
|
return raf(callback);
|
|
}
|
|
|
|
return {
|
|
add: addFunction,
|
|
force: forceProcessBatch
|
|
};
|
|
};
|
|
|
|
function Batch() {
|
|
var batch = {};
|
|
var size = 0;
|
|
var topLevel = 0;
|
|
var bottomLevel = 0;
|
|
|
|
function add(level, fn) {
|
|
if(!fn) {
|
|
fn = level;
|
|
level = 0;
|
|
}
|
|
|
|
if(level > topLevel) {
|
|
topLevel = level;
|
|
} else if(level < bottomLevel) {
|
|
bottomLevel = level;
|
|
}
|
|
|
|
if(!batch[level]) {
|
|
batch[level] = [];
|
|
}
|
|
|
|
batch[level].push(fn);
|
|
size++;
|
|
}
|
|
|
|
function process() {
|
|
for(var level = bottomLevel; level <= topLevel; level++) {
|
|
var fns = batch[level];
|
|
|
|
for(var i = 0; i < fns.length; i++) {
|
|
var fn = fns[i];
|
|
fn();
|
|
}
|
|
}
|
|
}
|
|
|
|
function getSize() {
|
|
return size;
|
|
}
|
|
|
|
return {
|
|
add: add,
|
|
process: process,
|
|
size: getSize
|
|
};
|
|
}
|