JavaScript性能优化|青训营

90 阅读3分钟

01.内存管理

内存管理流程分为三步:申请内存空间、使用内存空间和释放内存空间。

//申请
let obj = {};
//使用
obj.name="name";
//释放
obj = null;

在JavaScript中内存管理是自动的,我们在创建对象、数组的时候会自动分配内存空间,后续在代码执行过程中无法找到引用关系,这些对象就会被看做垃圾。另外代码中对象存在,而由于代码错误导致找不到该对象了,这也是垃圾。知道了有哪些垃圾,JavaScript执行引擎就会出来回收,这个过程就是JavaScript的垃圾回收。在JavaScript中可以访问到的对象就是可达对象(引用、作用域链),可达的标准就是从全局变量出发是否能找到。

GC的定义与作用

GC就是垃圾回收机制的简写,当GC工作的时候可以找到内存中的垃圾对象,然后对对象空间进行释放和回收,方便后续代码进行使用。那么GC中的垃圾是什么呢?

  1. 程序中不再需要使用的对象
    function func(){ name = "test"; return ${name} is a developer } func(); //当函数调用完后,不再需要使用name
  2. 程序中不能再访问到的对象
    function func(){ const name = "test"; return ${name} is a developer } func(); //当函数调用完后,外部空间访问不到name了

GC算法是什么

GC算法就是GC工作时查找和回收所遵循的规则,例如如何查找空间,如何释放空间,回收空间的过程中如何去分配。

常见的GC算法:

  • 引用计数
  • 标记清除
  • 标记整理
  • 分代回收

02.防抖和节流

在一些高频率事件触发的场景下不希望对应的事件处理函数多次执行,例如场景:

  1. 滚动事件
  2. 输入的模糊匹配
  3. 轮播图切换
  4. 点击操作
  5. ....

出现以上场景的原因是,浏览器默认情况下都会有自己的监听事件间隔,如果检测到多次的事件监听执行,那么就会造成不必要的资源浪费。这时就需要防抖和节流。

防抖

防抖指在高频的操作只识别一次点击,可以认为是第一次或最后一次。

/**
 * handle: 最终需要执行的事件监听
 * wait: 事件触发之后多久执行
 * immediate: 控制执行第一次还是最后一次,false是最后一次
 */
function myDebounce(handle,wait,immediate){
    if(typeof handle !== 'function') throw new Error('handle must be an function');
    if(typeof wait === 'undefined') wait = 300;
    if(typeof wait === 'boolean') {
        immediate = wait;
        wait = 300;
    } 
    if(typeof immediate !== 'boolean') immediate = false;
    let timer = null;
    return function proxy(...args){
        let self =this;
        init = immediate&&!timer;
        clearTimeout(timer);
        timer = setTimeout(()=>{
            timer = null;
            !init?handle.call(self,...args):null;
        },wait);
        //立即执行
        init?handle.call(self,...args):null;
    }
}

节流

节流指在高频的操作下可以自己设置频率,让本来会执行很多次的事件触发,按着定义的频率减少触发的次数。

function myThrottle(handle,wait){
    if(typeof handle !== 'function') throw new Error('handle must be an function');
    if(typeof wait === 'undefined') wait = 400;
    let previous = 0;
    let timer = null;
    return function proxy(...args){
        let now = new Date();
        let self = this;
        let interval = wait - (now - previous);
        if(interval <= 0){
            //是一个非高频的操作,可以执行handle
            clearTimeout(timer);
            timer = null;
            handle.call(self,...args);
            previous = new Date();
        }else if(!timer){
            //此时在定义的频率范围内,则不执行handle,这时候可以定义定时器,在规定时间后执行
            timer = setTimeout(()=>{
                clearTimeout(timer);
                timer = null;
                handle.call(self,...args);
                previous = new Date();
            },interval);
        }
    };