记一个闭包导致的内存泄漏问题
最近写代码碰到闭包导致的内存泄漏问题,记录一下
问题描述
问题发生在runJs函数中,该函数的功能是将js代码运行,返回运行结果,如下:
/**
* 运行js代码
* @param code js代码
* @returns {Promise<unknown>}
*/
export function runJs (code) {
return new Promise((resolve, reject) => {
let worker = new Worker("worker.js");
worker.postMessage(code);
worker.onmessage = (event) => {
resolve(event)
worker.terminate()
};
worker.onerror = (error) => {
reject(error)
worker.terminate()
}
})
}
在以上函数中,onmessage、onerror函数存在闭包,因为在onmessage和onerror函数中存在对外层函数中worker变量的引用。在外层函数执行完毕后,worker不会被垃圾回收,也就造成每执行一次runJs函数,就会产生一个Worker实例且不被释放
解决方案
一:使用一次性事件
/**
* 运行js代码
* @param code js代码
* @returns {Promise<unknown>}
*/
export function runJs (code) {
return new Promise((resolve, reject) => {
let worker = new Worker("worker.js");
worker.postMessage(code);
worker.addEventListener('message', event => {
resolve(event)
worker.terminate()
}, {
once: true
})
worker.addEventListener('error', error => {
reject(error)
worker.terminate()
}, {
once: true
})
})
}
二、手动释放:worker = null
/**
* 运行js代码
* @param code js代码
* @returns {Promise<unknown>}
*/
export function runJs (code) {
return new Promise((resolve, reject) => {
let worker = new Worker("worker.js");
worker.postMessage(code);
worker.onmessage = (event) => {
resolve(event)
worker.terminate()
worker = null
};
worker.onerror = (error) => {
reject(error)
worker.terminate()
worker = null
}
})
}