前言
5年的开发了,这几天试图看vue和react源码,看视频,看文档,看分析死磕源码,想明白框架这么写的由来。任何你认为没必要的判断都是填坑得来的,看不懂的只可能是你还没碰到。但...但是太难了,看了两个多星期了,雨里雾里的。看了后面忘了前面,脑内存不够用,无法处理那么深的嵌套。 有的说把我思想足够了,可优秀是在细节,思想早就被写的烂大街了,那些判断,嵌套,结构才是最值得学习的。
框架常用的,业务不常用的api
api | window | node |
---|---|---|
setImmediate | ❎ | ✅ |
requestAnimationFrame | ✅ | ❎ |
MessageChannel | ✅ | ✅ |
postMessage | ✅ | ❎ |
MutationObserver | ✅ | ❎ |
requestIdleCallback | ✅ | ❎ |
process.nextTick | ❎ | ✅ |
compositionstart | ✅ | ❎ |
逐一介绍
1 setImmediate
- node支持 浏览器支持的不好
- 异步宏任务
- setImmediate可以使用clearImmediate清除
- setTimeout优先级高于setImmediate(node eventloop先直线timer阶段,在执行check阶段)
2 requestAnimationFrame

- 浏览器都已经支持
- 如上每一帧渲染阶段分为上面六个阶段
- requestAnimationFrame 每帧必执行
- 如果以上6个阶段16ms内未执行完成就出现卡顿
3 MessageChannel
var channel = new MessageChannel();
var port1 = channel.port1;
var port2 = channel.port2;
port1.onmessage = function(event) {
console.log("port1收到来自port2的数据:" + event.data);
}
port2.onmessage = function(event) {
console.log("port2收到来自port1的数据:" + event.data);
}
port1.postMessage("发送给port2");
port2.postMessage("发送给port1");
- 浏览器已经支持
- new Messagechannel 返回一个对象 port1 和 prot2 都是只读
- port1.postMessage port2端口接收
- 异步执行
4 postMessage
- 浏览器两个window对象的通信
- 无同源限制,不同域名和端口都能通信
- 浏览器端支持,不同窗口或者父子窗口
targetWindow.postMessage(message, targetOrigin, [transfer]);
window.addEventListener("message", receiveMessage, false);
5 MutationObserver
- 可以监听DOM结构变化的接口
<div id="opop">
<div class="op"></div>
<div class="op"></div>
<div class="op op-node-change"></div>
</div>
<!--引用jqery-->
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js"></script>
<script>
var targetNode =document.getElementById('opop');
var observer = new MutationObserver(function(mutations) {
var $node = $('#opop .op:not(.op-node-change)');
$node.addClass('op-node-change test');
});
// 监控目标节点的变化
observer.observe(targetNode, { attributes: true, childList: true, subtree: true });
// 取消目标节点的监控
observer.disconnect();
</script>
6 requestIdleCallback
- 语法 var handle = window.requestIdleCallback(callback[, options])
- options = { timeout: 2000 } 配置如果超过2s就强制执行
- 方法将在浏览器的空闲时段内调用的函数排队
- 一个ID,可以把它传入 Window.cancelIdleCallback() 方法来结束回调。
7 process.nextTick
- node process的api
- Node的Event Loop 的六个阶段
阶段 | 概括 | eg |
---|---|---|
timer阶段 | 执行到期的setTimeout / setInterval队列回调 | |
I/O阶段 | 执行上轮残留的callback | 重点是上一轮 |
idle,prepare | 这个阶段仅在内部使用 | 应该是处理文本据点回收 |
poll阶段 | 获取新的I/O事件, 适当的条件下node将阻塞在这里 | 这一步决定下一步是 从timer阶段从头开始还是到下一check阶段 如果有遇到setTimeout / setInterval,则返回到timer阶段。如果遇到setImmediate,则前往check阶段。 |
check阶段 | 执行setImmediate()的回调函数。 | |
close阶段 | callbacks | ocket.on(‘close’, …) |
- 注意:上面六个阶段都不包括 process.nextTick() 独立于 Event Loop 之外的,它有一个自己的队列,当每个阶段完成后,如果存在 nextTick 队列,就会清空队列中的所有回调函数,并且优先于其他 microtask 执行。
8 compositionstart
- 相关事件 compositionend compositionupdate
- 监控汉字字符的输入
- 多用于监控汉字的输入 减少搜索请求
- 只能用dom3事件书写
<!DOCTYPE html>
<html>
<head>
<title>input</title>
</head>
<body>
<input class="input"/>
<script type="text/javascript">
document.querySelector('.input').addEventListener('compositionstart', function(e) {
console.log(11111, e)
}, false)
document.querySelector('.input').addEventListener('compositionupdate', function(e) {
console.log(2222, e)
}, false)
document.querySelector('.input').addEventListener('compositionend', function(e) {
console.log(33333, e)
}, false)
</script>
</body>
</html>