From 38a16246f0ff0da865de2bc58139ecb6cbf4721f Mon Sep 17 00:00:00 2001 From: hustcc Date: Wed, 30 Aug 2023 14:25:46 +0800 Subject: [PATCH] fix: memory leak when unbind --- __tests__/issue-17.spec.js | 29 +++++++++++++++++++++++++++++ __tests__/unbind.spec.js | 2 +- dist/size-sensor.min.js | 2 +- package.json | 2 +- src/sensorPool.js | 22 +++++++++++++--------- src/sensors/object.js | 6 ++++-- src/sensors/resizeObserver.js | 5 ++++- 7 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 __tests__/issue-17.spec.js diff --git a/__tests__/issue-17.spec.js b/__tests__/issue-17.spec.js new file mode 100644 index 0000000..5086be7 --- /dev/null +++ b/__tests__/issue-17.spec.js @@ -0,0 +1,29 @@ +import { clear, bind } from '../src'; +import { Sensors } from '../src/sensorPool'; + +describe('#17', () => { + // 创建 div + const div = document.createElement('div'); + document.body.appendChild(div); + div.innerHTML = `
`; + + const wrapper = document.getElementById('wrapper'); + + test('memory leak', () => { + const unbind1 = bind(wrapper, () => {}); + const unbind2 = bind(wrapper, () => {}); + + const id = wrapper.getAttribute('size-sensor-id'); + + expect(Object.keys(Sensors).length).toBe(1); + expect(Sensors[id]).not.toBeUndefined(); + + unbind1(); + expect(Object.keys(Sensors).length).toBe(1); + expect(Sensors[id]).not.toBeNull(); + + unbind2(); + expect(Object.keys(Sensors).length).toBe(0); + expect(Sensors[id]).toBeUndefined(); + }); +}); diff --git a/__tests__/unbind.spec.js b/__tests__/unbind.spec.js index 6892e11..a704887 100644 --- a/__tests__/unbind.spec.js +++ b/__tests__/unbind.spec.js @@ -21,6 +21,6 @@ describe('unbind', () => { expect(wrapper.getAttribute('size-sensor-id')).not.toBeNull(); unbind(); - expect(wrapper.getAttribute('size-sensor-id')).not.toBeNull(); + expect(wrapper.getAttribute('size-sensor-id')).toBeNull(); }); }); diff --git a/dist/size-sensor.min.js b/dist/size-sensor.min.js index 4ef1d95..46bb48b 100644 --- a/dist/size-sensor.min.js +++ b/dist/size-sensor.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self).sizeSensor={})}(this,function(e){"use strict";function s(o){var r=1 { const newId = id(); element.setAttribute(SizeSensorId, newId); - const sensor = createSensor(element); + const sensor = createSensor(element, () => clean(newId)); // add sensor into pool Sensors[newId] = sensor; @@ -43,14 +53,8 @@ export const getSensor = element => { */ export const removeSensor = sensor => { const sensorId = sensor.element.getAttribute(SizeSensorId); - - // remove attribute - sensor.element.removeAttribute(SizeSensorId); // remove event, dom of the sensor used sensor.destroy(); - // exist, then remove from pool - if (sensorId && Sensors[sensorId]) { - delete Sensors[sensorId]; - } + clean(sensorId); }; diff --git a/src/sensors/object.js b/src/sensors/object.js index a39834a..01415aa 100644 --- a/src/sensors/object.js +++ b/src/sensors/object.js @@ -4,9 +4,9 @@ */ import debounce from '../debounce'; -import { SensorClassName, SensorTabIndex } from '../constant'; +import { SensorClassName, SensorTabIndex, SizeSensorId } from '../constant'; -export const createSensor = element => { +export const createSensor = (element, whenDestroy) => { let sensor = undefined; // callback let listeners = []; @@ -85,8 +85,10 @@ export const createSensor = element => { // remove dom sensor.parentNode.removeChild(sensor); // initial variable + element.removeAttribute(SizeSensorId); sensor = undefined; listeners = []; + whenDestroy && whenDestroy(); } }; diff --git a/src/sensors/resizeObserver.js b/src/sensors/resizeObserver.js index 4cd3602..9a4ac5e 100644 --- a/src/sensors/resizeObserver.js +++ b/src/sensors/resizeObserver.js @@ -3,9 +3,10 @@ * Contract: i@hust.cc */ +import { SizeSensorId } from '../constant'; import debounce from '../debounce'; -export const createSensor = element => { +export const createSensor = (element, whenDestroy) => { let sensor = undefined; // callback let listeners = []; @@ -56,6 +57,8 @@ export const createSensor = element => { listeners = []; sensor = undefined; + element.removeAttribute(SizeSensorId); + whenDestroy && whenDestroy(); }; /**