Skip to content
Snippets Groups Projects
Select Git revision
  • 3ff823a63e87941ee184b8e844d3c4a19f6b52d8
  • master default protected
  • rednatco-v2
  • base-pairs-ladder
  • rednatco
  • test
  • ntc-tube-uniform-color
  • ntc-tube-missing-atoms
  • restore-vertex-array-per-program
  • watlas2
  • dnatco_new
  • cleanup-old-nodejs
  • webmmb
  • fix_auth_seq_id
  • update_deps
  • ext_dev
  • ntc_balls
  • nci-2
  • plugin
  • bugfix-0.4.5
  • nci
  • v0.5.0-dev.1
  • v0.4.5
  • v0.4.4
  • v0.4.3
  • v0.4.2
  • v0.4.1
  • v0.4.0
  • v0.3.12
  • v0.3.11
  • v0.3.10
  • v0.3.9
  • v0.3.8
  • v0.3.7
  • v0.3.6
  • v0.3.5
  • v0.3.4
  • v0.3.3
  • v0.3.2
  • v0.3.1
  • v0.3.0
41 results

scheduler.ts

Blame
  • user avatar
    David Sehnal authored
    0c7c82e0
    History
    scheduler.ts 7.24 KiB
    /**
     * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
     *
     * @author David Sehnal <david.sehnal@gmail.com>
     */
    
    /**
     * setImmediate polyfill adapted from https://github.com/YuzuJS/setImmediate
     * Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola
     * MIT license.
     */
    
    function createImmediateActions() {
        type Callback = (...args: any[]) => void;
        type Task = { callback: Callback, args: any[] }
    
        const tasksByHandle: { [handle: number]: Task } = { };
        const doc = typeof document !== 'undefined' ? document : void 0;
    
        let currentlyRunningATask = false;
        let nextHandle = 1; // Spec says greater than zero
        let registerImmediate: ((handle: number) => void);
    
        function setImmediate(callback: Callback, ...args: any[]) {
          // Callback can either be a function or a string
          if (typeof callback !== 'function') {
            callback = new Function('' + callback) as Callback;
          }
          // Store and register the task
          const task = { callback: callback, args: args };
          tasksByHandle[nextHandle] = task;
          registerImmediate(nextHandle);
          return nextHandle++;
        }
    
        function clearImmediate(handle: number) {
            delete tasksByHandle[handle];
        }
    
        function run(task: Task) {
            const callback = task.callback;
            const args = task.args;
            switch (args.length) {
            case 0:
                callback();
                break;
            case 1:
                callback(args[0]);
                break;
            case 2:
                callback(args[0], args[1]);
                break;
            case 3:
                callback(args[0], args[1], args[2]);
                break;
            default:
                callback.apply(undefined, args);
                break;
            }
        }
    
        function runIfPresent(handle: number) {
            // From the spec: 'Wait until any invocations of this algorithm started before this one have completed.'
            // So if we're currently running a task, we'll need to delay this invocation.
            if (currentlyRunningATask) {
                // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a
                // 'too much recursion' error.
                setTimeout(runIfPresent, 0, handle);
            } else {
                const task = tasksByHandle[handle];
                if (task) {
                    currentlyRunningATask = true;
                    try {
                        run(task);
                    } finally {
                        clearImmediate(handle);
                        currentlyRunningATask = false;
                    }
                }
            }
        }
    
        function installNextTickImplementation() {
            registerImmediate = function(handle) {
                process.nextTick(function () { runIfPresent(handle); });
            };
        }
    
        function canUsePostMessage() {
            // The test against `importScripts` prevents this implementation from being installed inside a web worker,
            // where `global.postMessage` means something completely different and can't be used for this purpose.
            const global = typeof window !== 'undefined' ? window as any : void 0;
            if (global && global.postMessage && !global.importScripts) {
                let postMessageIsAsynchronous = true;
                const oldOnMessage = global.onmessage;
                global.onmessage = function() {
                    postMessageIsAsynchronous = false;
                };
                global.postMessage('', '*');
                global.onmessage = oldOnMessage;
                return postMessageIsAsynchronous;
            }
        }
    
        function installPostMessageImplementation() {
            // Installs an event handler on `global` for the `message` event: see
            // * https://developer.mozilla.org/en/DOM/window.postMessage
            // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
    
            const messagePrefix = 'setImmediate$' + Math.random() + '$';
            const global = typeof window !== 'undefined' ? window as any : void 0;
            const onGlobalMessage = function(event: any) {
                if (event.source === global &&
                    typeof event.data === 'string' &&
                    event.data.indexOf(messagePrefix) === 0) {
                    runIfPresent(+event.data.slice(messagePrefix.length));
                }
            };
    
            if (window.addEventListener) {
                window.addEventListener('message', onGlobalMessage, false);
            } else {
                (window as any).attachEvent('onmessage', onGlobalMessage);
            }
    
            registerImmediate = function(handle) {
                window.postMessage(messagePrefix + handle, '*');
            };
        }
    
        function installMessageChannelImplementation() {
            const channel = new MessageChannel();
            channel.port1.onmessage = function(event) {
                const handle = event.data;
                runIfPresent(handle);
            };
    
            registerImmediate = function(handle) {
                channel.port2.postMessage(handle);
            };
        }
    
        function installReadyStateChangeImplementation() {
            const html = doc!.documentElement;
            registerImmediate = function(handle) {
                // Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted
                // into the document. Do so, thus queuing up the task. Remember to clean up once it's been called.
                let script = doc!.createElement('script') as any;
                script.onreadystatechange = function () {
                    runIfPresent(handle);
                    script.onreadystatechange = null;
                    html.removeChild(script);
                    script = null;
                };
                html.appendChild(script);
            };
        }
    
        function installSetTimeoutImplementation() {
            registerImmediate = function(handle) {
                setTimeout(runIfPresent, 0, handle);
            };
        }
    
        // Don't get fooled by e.g. browserify environments.
        if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
            // For Node.js before 0.9
            installNextTickImplementation();
        } else if (canUsePostMessage()) {
            // For non-IE10 modern browsers
            installPostMessageImplementation();
        } else if (typeof MessageChannel !== 'undefined') {
            // For web workers, where supported
            installMessageChannelImplementation();
        } else if (doc && 'onreadystatechange' in doc.createElement('script')) {
            // For IE 6–8
            installReadyStateChangeImplementation();
        } else {
            // For older browsers
            installSetTimeoutImplementation();
        }
    
        return {
            setImmediate,
            clearImmediate
        };
    }
    
    const immediateActions = (function () {
        if (typeof setImmediate !== 'undefined') {
            if (typeof window !== 'undefined') {
                return { setImmediate: (handler: any, ...args: any[]) => window.setImmediate(handler, ...args as any), clearImmediate: (handle: any) => window.clearImmediate(handle) };
            } else return { setImmediate, clearImmediate }
        }
        return createImmediateActions();
    }());
    
    function resolveImmediate(res: () => void) {
        immediateActions.setImmediate(res);
    }
    
    export default {
        immediate: immediateActions.setImmediate,
        clearImmediate: immediateActions.clearImmediate,
    
        immediatePromise() { return new Promise<void>(resolveImmediate); }
    };