futoin-asyncsteps
Version:
Mimic traditional threads in single threaded event loop
137 lines (113 loc) • 3.75 kB
JavaScript
;
/**
* @file
* @author Andrey Galkin <andrey@futoin.org>
*
*
* Copyright 2014-2017 FutoIn Project (https://futoin.org)
* Copyright 2014-2017 Andrey Galkin <andrey@futoin.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* globals GenericFunc */
/**
* Neutral interface to event scheduler
* @member AsyncTool
*/
exports = module.exports = {};
/* istanbul ignore if */
if ( typeof setImmediate === 'undefined' ) {
// Wrapper for simple setTimeout
// ---
exports.callLater = ( func, timeout_ms ) => setTimeout( func, timeout_ms );
exports.cancelCall = ( func ) => clearTimeout( func );
// Workaround for security-delayed setTimeout
// ---
// workaround possible multiple instances of AsyncSteps
window._FutoInEventLoopQueue = window._FutoInEventLoopQueue || [];
const TIME_LIMIT = 10; // support browser with 100ms precision
const queue = window._FutoInEventLoopQueue;
const performance = window.performance;
let process_handle = null;
const sched_immed_process = () => {
if ( process_handle ) {
clearTimeout( process_handle );
}
process_handle = setTimeout( process_queue, 0 );
};
const process_queue = () => {
process_handle = null;
const end_time = performance.now() + TIME_LIMIT;
while ( queue.length ) {
const r = queue.shift();
try {
r();
} catch ( e ) {
sched_immed_process();
throw e;
}
if ( performance.now() >= end_time ) {
sched_immed_process();
break;
}
}
};
exports.callImmediate = ( func ) => {
if ( !queue.length ) {
sched_immed_process();
}
const handle = () => {
func();
}; // same func can be added multiple times
queue.push( handle );
return handle;
};
exports.cancelImmediate = ( handle ) => {
const i = queue.indexOf( handle );
if ( i >= 0 ) {
queue.splice( i, 1 );
}
};
} else {
/**
* Wrapper for setTimeout()
* @param {GenericFunc} func - callback to execute
* @param {number} [timeout_ms] - optional timeout in ms
* @returns {object} - timer handle
* @alias AsyncTool.callLater
*/
exports.callLater = ( func, timeout_ms ) => setTimeout( func, timeout_ms );
/**
* Wrapper for clearTimeout()/clearImmediate()
* @param {object} handle - Handle returned from AsyncTool.callLater
* @alias AsyncTool.cancelCall
*/
exports.cancelCall = ( handle ) => {
clearTimeout( handle );
};
/**
* Wrapper for setImmediate()
* @param {GenericFunc} func - callback to execute
* @returns {object} - timer handle
* @alias AsyncTool.callImmediate
*/
exports.callImmediate = ( func ) => setImmediate( func );
/**
* Wrapper for clearImmediate()
* @param {object} handle - Handle returned from AsyncTool.callImmediate
* @alias AsyncTool.cancelImmediate
*/
exports.cancelImmediate = ( handle ) => {
clearImmediate( handle );
};
}