You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					67 lines
				
				2.1 KiB
			
		
		
			
		
	
	
					67 lines
				
				2.1 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// rawAsap provides everything we need except exception management.
							 | 
						||
| 
								 | 
							
								var rawAsap = require("./raw");
							 | 
						||
| 
								 | 
							
								// RawTasks are recycled to reduce GC churn.
							 | 
						||
| 
								 | 
							
								var freeTasks = [];
							 | 
						||
| 
								 | 
							
								// We queue errors to ensure they are thrown in right order (FIFO).
							 | 
						||
| 
								 | 
							
								// Array-as-queue is good enough here, since we are just dealing with exceptions.
							 | 
						||
| 
								 | 
							
								var pendingErrors = [];
							 | 
						||
| 
								 | 
							
								var requestErrorThrow = rawAsap.makeRequestCallFromTimer(throwFirstError);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function throwFirstError() {
							 | 
						||
| 
								 | 
							
								    if (pendingErrors.length) {
							 | 
						||
| 
								 | 
							
								        throw pendingErrors.shift();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Calls a task as soon as possible after returning, in its own event, with priority
							 | 
						||
| 
								 | 
							
								 * over other events like animation, reflow, and repaint. An error thrown from an
							 | 
						||
| 
								 | 
							
								 * event will not interrupt, nor even substantially slow down the processing of
							 | 
						||
| 
								 | 
							
								 * other events, but will be rather postponed to a lower priority event.
							 | 
						||
| 
								 | 
							
								 * @param {{call}} task A callable object, typically a function that takes no
							 | 
						||
| 
								 | 
							
								 * arguments.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								module.exports = asap;
							 | 
						||
| 
								 | 
							
								function asap(task) {
							 | 
						||
| 
								 | 
							
								    var rawTask;
							 | 
						||
| 
								 | 
							
								    if (freeTasks.length) {
							 | 
						||
| 
								 | 
							
								        rawTask = freeTasks.pop();
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        rawTask = new RawTask();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    rawTask.task = task;
							 | 
						||
| 
								 | 
							
								    rawAsap(rawTask);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// We wrap tasks with recyclable task objects.  A task object implements
							 | 
						||
| 
								 | 
							
								// `call`, just like a function.
							 | 
						||
| 
								 | 
							
								function RawTask() {
							 | 
						||
| 
								 | 
							
								    this.task = null;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// The sole purpose of wrapping the task is to catch the exception and recycle
							 | 
						||
| 
								 | 
							
								// the task object after its single use.
							 | 
						||
| 
								 | 
							
								RawTask.prototype.call = function () {
							 | 
						||
| 
								 | 
							
								    try {
							 | 
						||
| 
								 | 
							
								        this.task.call();
							 | 
						||
| 
								 | 
							
								    } catch (error) {
							 | 
						||
| 
								 | 
							
								        if (asap.onerror) {
							 | 
						||
| 
								 | 
							
								            // This hook exists purely for testing purposes.
							 | 
						||
| 
								 | 
							
								            // Its name will be periodically randomized to break any code that
							 | 
						||
| 
								 | 
							
								            // depends on its existence.
							 | 
						||
| 
								 | 
							
								            asap.onerror(error);
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								            // In a web browser, exceptions are not fatal. However, to avoid
							 | 
						||
| 
								 | 
							
								            // slowing down the queue of pending tasks, we rethrow the error in a
							 | 
						||
| 
								 | 
							
								            // lower priority turn.
							 | 
						||
| 
								 | 
							
								            pendingErrors.push(error);
							 | 
						||
| 
								 | 
							
								            requestErrorThrow();
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    } finally {
							 | 
						||
| 
								 | 
							
								        this.task = null;
							 | 
						||
| 
								 | 
							
								        freeTasks[freeTasks.length] = this;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 |