MessageChannel, MutationObserver种种

1,074 阅读3分钟

前言

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>