exportvar asap = functionasap(callback, arg) { queue[len] = callback; // queue 是一个数组,在这里模拟等待队列.队列是先进先出的, 而 len 是一个变量用于记录长度 queue[len + 1] = arg; // 将当前的 Promise 存在队列里(入队) len += 2; // 一次时间占两个位置 第一个位置是回调第二个位置是参数 if (len === 2) { // If len is 2, that means that we need to schedule an async flush. // If additional callbacks are queued before the queue is flushed, they // will be processed by this flush that we are scheduling. // 如果只有两个那么此次只需要处理当前事件即可,如果队列长度不止两个那么说明还有其他的事件等待处理 (ps 为什么用一个变量来做数组/ //长度以为在源码中queue的值是Array(1000) 无法通过数组长度拿到实际队列长度) if (customSchedulerFn) { // 如果自定义调度器存在则使用自定义调度器如果不存在那么使用默认调度器 customSchedulerFn(flush); // 使用 es6-promise 公开了一个Promise._setScheduler属性来设置自定义调度器 } else { scheduleFlush(); // 使用默认调度器直接处理当前事件 } } };
scheduleFlush
事件调度器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
//这段if else 用来兼容多种运行环境
let scheduleFlush; // Decide what async method to use to triggering processing of queued callbacks: // 决定使用什么异步的方法来处理回调 if (isNode) { // 如果在node (isNode 是一连串判断判断一些全局变量是否存在) scheduleFlush = useNextTick(); // process.nextTick(flush) } elseif (BrowserMutationObserver) { scheduleFlush = useMutationObserver(); // 使用 BrowserMutationObserver 这个浏览器 api } elseif (isWorker) { scheduleFlush = useMessageChannel(); // 如果支持web worker 则使用 MessageChannel } elseif (browserWindow === undefined && typeofrequire === "function") { scheduleFlush = attemptVertx(); // 桌面程序 } else { scheduleFlush = useSetTimeout(); // 最终办法定时器. }
// 这个比较简单了,没什么好解释的了 functionuseSetTimeout() { // Store setTimeout reference so es6-promise will be unaffected by // other code modifying setTimeout (like sinon.useFakeTimers()) const globalSetTimeout = setTimeout; return() =>globalSetTimeout(flush, 1); }
事件调度处理器看完了那么需要看 flush 方法.看看这个方法究竟做了什么
1 2 3 4 5 6 7 8 9 10 11 12 13 14
functionflush() { for (let i = 0; i < len; i += 2) { // += 2 是为了跳过 poromise 元素 queue 的构成是这样的 [callback, promise] let callback = queue[i]; let arg = queue[i + 1];