资讯专栏INFORMATION COLUMN

【debug】事件绑定代码中的一个低级错误导致的内存泄漏

XboxYan / 1944人阅读

摘要:静下来想了想发现我犯了一个低级错误。上面的代码中函数是在这个函数闭包中申明的,在这个函数执行完毕后,由于它被绑上了事件,引用并不为,所以没有被回收。

最近写一个web应用的图片上传功能,里面有这么个场景:点击上传按钮,呼出file input框,选择完图片进行前端压缩然后上传,完毕后将返回的图片链接展示给用户。这个功能很常见,但是在这里却翻了船,所以专门记录一下这个bug。

我是这么写的(vue代码片段):

methods: {
    clickInput(item, e) {
        this.uploadItem = e.target.parentNode;
        this.item = item;
        let input = this.input = this.uploadItem.querySelector("input");

        async function changeHook() {
            let compress = new CompressImg({
                maxSize: 500 * 1024,
                quality: 0.2,
                files: this.input.files,
            })

            let blob = await compress.getBlob();
            if (blob) {
                this.uploadImg(blob);
            }
        }

        input.removeEventListener("change", changeHook);
        input.addEventListener("change", changeHook);
        input.click();
    },
}

此处写的很僵硬,直接在html中给input绑定事件即可,没必要动态绑定 捂脸

compressImg是参考网上大牛的方法用canvas的api进行前端压缩,具体见我的gist:https://gist.github.com/win5d...

为了防止绑定多个事件,这里先remove再add,看起来好像没毛病,看了下控制台,发现上传触发了多次,excuse me?

回头检查了一下代码,感觉没毛病啊,开始还以为是async函数惹的祸,改成普通函数发现还是有问题。静下来想了想发现我犯了一个低级错误。

上面的代码中changeHook函数是在clickInput这个函数(闭包)中申明的,在这个函数执行完毕后,由于它被绑上了事件,引用并不为null,所以没有被回收。下一次点击时又回创建一个新的changeHook函数,虽然都叫changeHook,但这两个函数在不同的闭包之中,占据不同的内存,调用removeEventListener也是然并卵,每次触发clickInput都会造成一次内存泄漏。

只需要把函数申明放到外面即可:




在函数里面申明函数,这个写法我也知道很坑爹,由于这个函数只在这个方法用到,而且强迫症不想在data里申明很多变量,偷懒不想处理参数传递,结果搞出这么个低级错误。强迫症得治,偷了的懒都得还,rua!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89187.html

相关文章

  • JS垃圾回收与内存泄漏

    摘要:介绍浏览器的具有自动垃圾回收机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。中的内存泄漏问题程序的内存溢出后,会使某一段函数体永远失效取决于当时的代码运行到哪一个函数,通常表现为程序突然卡死或程序出现异常。 showImg(https://segmentfault.com/img/remote/1460000018932880?w=4400&h=3080); 1. 介绍 浏...

    xiaolinbang 评论0 收藏0
  • 【前端进阶之路】内存基本知识

    摘要:在运行脚本时,需要显示的指定对象。大对象区每一个区域都是由一组内存页构成的。这里是唯一拥有执行权限的内存区。换句话说,是该对象被之后所能回收到内存的总和。一旦活跃对象已被移出,则在旧的半空间中剩下的任何死亡对象被丢弃。 内存管理 本文以V8为背景 对之前的文章进行重新编辑,内容做了很多的调整,使其具有逻辑更加紧凑,内容更加全面。 1. 基础概念 1.1 生命周期 不管什么程序语言,内存...

    Simon_Zhou 评论0 收藏0
  • JavaScript如何工作:内存管理+如何处理4个常见内存泄漏

    摘要:本系列的第一篇文章简单介绍了引擎运行时间和堆栈的调用。编译器将插入与操作系统交互的代码,并申请存储变量所需的堆栈字节数。当函数调用其他函数时,每个函数在调用堆栈时获得自己的块。因此,它不能为堆栈上的变量分配空间。 本系列的第一篇文章简单介绍了引擎、运行时间和堆栈的调用。第二篇文章研究了谷歌V8 JavaScript引擎的内部机制,并介绍了一些编写JavaScript代码的技巧。 在这第...

    anRui 评论0 收藏0

发表评论

0条评论

XboxYan

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<