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; | ||
|  |     } | ||
|  | }; |