asap 原理分析
什么是asap?
asap是as soon as possible的缩写,在Node和浏览器环境下能将回调函数以高优先级任务来执行(下一个事件循环之前)。Promise/A+的异步任务实现就是基于asap这个库。
ASAP会努力的在IO,重排,重绘等事件之前调度任务,也就是常说的会把任务放进微任务队列执行。
usage
asap(function () {
// ...
});
实现
定义全局变量
// 任务队列
var queue = [];
// 一旦有任务进行就置为true,直到本次队列清空才置为false
var flushing = false;
//requestFlush是一个方法,依据浏览器支持的特性不同会选择不同的API去实现,它会尝试清空任务队列。
var requestFlush;
//标记任务队列中下一个任务的位置
var index = 0;
// 防止内存耗尽,任务队列将定期 //截断已经完成的任务,capacity是任务的最大容量
var capacity = 1024;
flush 清空任务队列
function flush() {
while (index < queue.length) {
var currentIndex = index;
index = index + 1;
queue[currentIndex].call();
if (index > capacity) {
for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
queue[scan] = queue[scan + index];
}
queue.length -= index;
index = 0;
}
}
queue.length = 0;
index = 0;
flushing = false;
}
可以看到flush 用while循环处理任务队列,直到任务队列为空。任务执行完之后把queue等变量重置。
在flush运行过程中如果有其他地方调用了asap,会将任务加入queue,也就是说queue是动态添加的,但是flush只会运行一次,因为rawAsap保证了requestFlush方法只能调用一次
requestFlush是如何实现的?
requestFlush 是基于MutationObserver实现的,如果浏览器不支持该API,会选择使用定时器实现
var scope = typeof global !== "undefined" ? global : self;
var BrowserMutationObserver = scope.MutationObserver || scope.WebKitMutationObserver;
if (typeof BrowserMutationObserver === "function") {
requestFlush = makeRequestCallFromMutationObserver(flush);
}else{
requestFlush = makeRequestCallFromTimer(flush);
}
makeRequestCallFromMutationObserver
创建一个空的文本节点,监听其characterData属性的变化,修改node.data属性触发callback
function makeRequestCallFromMutationObserver(callback) {
var toggle = 1;
var observer = new BrowserMutationObserver(callback);
var node = document.createTextNode("");
observer.observe(node, {characterData: true});
return function requestCall() {
toggle = -toggle;
node.data = toggle;
};
}
makeRequestCallFromTimer
function makeRequestCallFromTimer(callback) {
return function requestCall() {
var timeoutHandle = setTimeout(handleTimer, 0);
var intervalHandle = setInterval(handleTimer, 50);
function handleTimer() {
clearTimeout(timeoutHandle);
clearInterval(intervalHandle);
callback();
}
};
}
MessageChannel 实现任务调度
通过消息通道也可以实现,但是该Api有些浏览器不支持
function makeRequestCallFromMessageChannel(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = callback;
return function requestCall() {
channel.port2.postMessage(0);
};
}
node环境实现方式一样,只是异步回调使用的是 process.nextTick和setImmediate
asap 原理分析
什么是asap?
asap是as soon as possible的缩写,在Node和浏览器环境下能将回调函数以高优先级任务来执行(下一个事件循环之前)。Promise/A+的异步任务实现就是基于asap这个库。
ASAP会努力的在IO,重排,重绘等事件之前调度任务,也就是常说的会把任务放进微任务队列执行。
usage
实现
定义全局变量
flush 清空任务队列
可以看到flush 用while循环处理任务队列,直到任务队列为空。任务执行完之后把queue等变量重置。
requestFlush是如何实现的?
requestFlush 是基于
MutationObserver实现的,如果浏览器不支持该API,会选择使用定时器实现makeRequestCallFromMutationObserver
创建一个空的文本节点,监听其characterData属性的变化,修改node.data属性触发callback
makeRequestCallFromTimer
MessageChannel 实现任务调度
通过消息通道也可以实现,但是该Api有些浏览器不支持
node环境实现方式一样,只是异步回调使用的是 process.nextTick和setImmediate