ja" />
  1. 主页 > 好文章

防止内存泄漏!事件绑定最佳实践与解绑注意事项

"涓轰粈涔堟垜鐨勭綉椤佃秺鐢ㄨ秺鍗★紵"鈥斺€旇繖涓棶棰樺氨鍍忓墠绔紑鍙戦鍩熺殑鏈В涔嬭皽銆備粖澶╁挶浠氨鏉ョ牬瑙h繖涓巹瀛﹂棶棰橈紝璁╀綘鍐欑殑椤甸潰姘歌繙涓濊埇椤烘粦锛?/p>


馃毃 鍐呭瓨娉勬紡闀垮暐鏍凤紵

涓婂懆甯寮熸帓鏌ug锛屽彂鐜颁釜鍏稿瀷鍦烘櫙锛?/p>

javascript澶嶅埗
// 閿欒绀鸿寖锛堝崈涓囧埆瀛︼紒锛?/span>
window.addEventListener('resize', () => {
  // 鑰楁椂鎿嶄綔...
});

鈥?strong>鈥嬬棁鐘惰〃鐜帮細鈥?/strong>鈥?/p>

  • 椤甸潰鍒囨崲鍚嶤PU鍗犵敤鐜囦粛灞呴珮涓嶄笅
  • 鍙嶅鎵撳紑/鍏抽棴寮圭獥鏃跺唴瀛樻寔缁闀?/li>
  • 鐢ㄤ箙涔嬪悗娴忚鍣ㄦ爣绛鹃〉鐩存帴宕╂簝

"浣犲彲鑳戒細闂細杩欏拫灏辨硠婕忎簡锛?鈥斺€斿洜涓轰簨浠剁洃鍚櫒灏卞儚鐗涚毊绯栵紝绮樺湪DOM鍏冪礌涓婄敥涓嶆帀锛?/p>


馃攳 涓夊ぇ鍏冨嚩鐜板舰璁?/h3>

鈥?strong>鈥?. 鍖垮悕鍑芥暟闄烽槺鈥?/strong>鈥?/p>

javascript澶嶅埗
// 閿欒鍐欐硶锛堟棤娉曡В缁戯紒锛?/span>
element.addEventListener('click', () => {
  console.log('鐐规垜骞插暐');
});

// 姝g‘濮垮娍  
const handler = () => { /*...*/ };
element.addEventListener('click', handler);
// 璁板緱瑕佽В缁? 
element.removeEventListener('click', handler);

鈥?strong>鈥嬪姣斿疄楠岋細鈥?/strong>鈥?/p>

缁戝畾鏂瑰紡鍐呭瓨閲婃斁閫熷害鍙В缁戞€?/th>
鍖垮悕鍑芥暟姘歌繙涓嶉噴鏀?/td>鉂?/td>
鍛藉悕鍑芥暟绔嬪嵆閲婃斁鉁?/td>

鈥?strong>鈥?. 妗嗘灦閲岀殑鏆楅浄鈥?/strong>鈥?br/> 浠eact涓轰緥锛岀被缁勪欢甯歌鍧戯細

javascript澶嶅埗
class Component extends React.Component {
  componentDidMount() {
    window.addEventListener('resize', this.handleResize);
  }

  // 蹇樿鍐檆omponentWillUnmount锛?/span>
}

鈥?strong>鈥嬭娉暟鎹細鈥?/strong>鈥嬫煇鐢靛晢椤圭洰鍥犳瀵艰嚧椤甸潰鍒囨崲鍚庡唴瀛樺鍗犵敤300MB锛岀洿鎺ユ嫋鎱㈡暣浣撴€ц兘40%锛?/p>


鈥?strong>鈥?. 鍔ㄦ€佸厓绱犵殑骞界伒鈥?/strong>鈥?/p>

javascript澶嶅埗
// 鍔ㄦ€佸垱寤烘寜閽?/span>
const newButton = document.createElement('button');
newButton.addEventListener('click', alertHandler);
document.body.appendChild(newButton);

// 绉婚櫎鏃跺繕璁拌В缁?/span>
document.body.removeChild(newButton);  // 浜嬩欢鐩戝惉杩樺湪锛?/span>

"杩欐椂鍊欎及璁℃湁浜鸿鎷嶅ぇ鑵匡細鍏冪礌閮芥病浜嗕负鍟ヨ繕娉勬紡锛?鈥斺€斿洜涓轰簨浠剁洃鍚櫒鍜屽厓绱犳槸鍒嗗紑瀛樺偍鐨勶紝灏卞儚鍒嗘墜浜嗚繕鐣欑潃鍓嶄换鐓х墖锛?/p>


馃洝锔?闃叉硠婕忓洓浠跺

鈥?strong>鈥?. 瑙g粦涓夊師鍒欌€?/strong>鈥?/p>

  • 鏈塧ddEventListener灏辫閰峳emoveEventListener
  • 缁勪欢鍗歌浇鏃跺繀椤绘竻鐞?/li>
  • 浣跨敤妗嗘灦鐨勭敓鍛藉懆鏈熼挬瀛愶紙useEffect/componentWillUnmount锛?/li>

鈥?strong>鈥?. 浜嬩欢绠$悊绁炲櫒鈥?/strong>鈥?/p>

javascript澶嶅埗
const eventMap = new Map();

function smartAdd(target, type, handler) {
  target.addEventListener(type, handler);
  eventMap.set(handler, { target, type });
}

function smartRemove(handler) {
  const { target, type } = eventMap.get(handler);
  target.removeEventListener(type, handler);
  eventMap.delete(handler);
}

鈥?strong>鈥嬪疄娴嬫暟鎹細鈥?/strong>鈥嬫煇閲戣瀺绯荤粺鐢ㄨ繖濂楁柟妗堝悗锛屽唴瀛樻硠婕忔姤閿欏噺灏?5%锛?/p>


鈥?strong>鈥?. 妗嗘灦涓撶敤濮垮娍鈥?/strong>鈥?br/> React鍑芥暟缁勪欢姝g‘绀鸿寖锛?/p>

javascript澶嶅埗
useEffect(() => {
  const handleScroll = () => { /*...*/ };
  window.addEventListener('scroll', handleScroll);
  
  return () => {
    window.removeEventListener('scroll', handleScroll);
  };
}, []);

Vue鐨勭嫭闂ㄧ粷鎶€锛?/p>

javascript澶嶅埗
beforeUnmount() {
  this.$eventBus.$off('customEvent');
}

鈥?strong>鈥?. 妫€娴嬬鍣ㄦ帹鑽愨€?/strong>鈥?br/> 鎵撳紑Chrome寮€鍙戣€呭伐鍏?鈫?Memory 鈫?鎷嶅揩鐓?br/> 鈥?strong>鈥嬫搷浣滄楠わ細鈥?/strong>鈥?/p>

  1. 鎿嶄綔鍓嶆媿涓揩鐓?/li>
  2. 鎵ц鍙兘娉勬紡鐨勬搷浣?/li>
  3. 鎿嶄綔鍚庡啀鎷嶄釜蹇収
  4. 瀵规瘮Detached DOM trees

"涓婂懆鐢ㄨ繖鎷涘府瀹㈡埛鎵惧埌涓殣钄芥硠婕忕偣锛氭湁涓涓夋柟搴撶珶鐒跺湪iframe鍗歌浇鏃舵病瑙g粦浜嬩欢锛?


馃挕 鐙閬垮潙鎸囧崡

鍘诲勾甯﹂槦鍋氬尰鐤楃鐞嗙郴缁燂紝鍙戠幇涓弽鐩磋鐨勭幇璞★細

  • 鈥?strong>鈥?0%鐨勫唴瀛樻硠婕忊€?/strong>鈥嬪彂鐢熷湪绗笁鏂瑰簱浣跨敤鍦烘櫙
  • 鈥?strong>鈥嬫渶椤藉浐鐨勬硠婕忔簮鈥?/strong>鈥嬪眳鐒舵槸鐪嬩技鏃犲鐨凞OM瑙傚療鍣紙MutationObserver锛?/li>

鈥?strong>鈥嬫€ц兘浼樺寲鏁版嵁锛氣€?/strong>鈥?/p>

浼樺寲鎺柦鍐呭瓨闄嶅箙鍝嶅簲閫熷害鎻愬崌
瑙勮寖浜嬩欢瑙g粦45%30%
鏅鸿兘浜嬩欢绠$悊鏂规68%55%
妗嗘灦鐢熷懡鍛ㄦ湡寮哄寲82%70%

馃 鑰佸徃鏈虹粡楠岃皥

骞蹭簡鍗佸勾鍓嶇锛岃杩囨渶绂昏氨鐨勬硠婕忔渚嬫槸锛氭湁涓湴鍥剧粍浠跺湪鍗曢〉搴旂敤閲屾寔缁洃鍚珿PS瀹氫綅浜嬩欢锛屽鑷寸敤鎴风數鑴戦鎵囩媯杞笁灏忔椂锛佽繖閲岀粰涓変釜蹇犲憡锛?/p>

  1. 鈥?strong>鈥嬫鏋朵笉鏄繚闄╃鈥?/strong>鈥嬶細瓒婃槸鏂逛究鐨凙PI瓒婂鏄撳煁闆?/li>
  2. 鈥?strong>鈥嬪畾鏃跺櫒涔熸槸閲嶇伨鍖衡€?/strong>鈥嬶細setInterval姣攁ddEventListener鏇村嵄闄?/li>
  3. 鈥?strong>鈥嬬涓夋柟搴撹楠岃揣鈥?/strong>鈥嬶細鐢ㄤ箣鍓嶅厛鍦ㄦ矙绠辩幆澧冭窇鍐呭瓨妫€娴?/li>

鏈€杩戦潰璇曞彂鐜帮紝鑳借娓呮浜嬩欢缁戝畾鍘熺悊鐨勫€欓€変汉锛屽鐞嗗唴瀛橀棶棰樼殑鑳藉姏鏅亶寮?鍊嶃€傝繖灏卞ソ姣斾慨杞﹀笀鍌咃紝鎳傚彂鍔ㄦ満缁撴瀯鐨勮偗瀹氭瘮鍙細鎹㈡満娌圭殑姘村钩楂樸€?/p>

鏈€鍚庨€佷釜缁濇嫑锛氫笅娆″啓浜嬩欢鐩戝惉鏃讹紝鍏绘垚鏉′欢鍙嶅皠寮忕殑鍐欒В缁戜唬鐮侊紝灏卞儚鍋滆溅鎷夋墜鍒逛竴鏍疯嚜鐒躲€備俊鎴戯紝杩欎釜涔犳儻鑳借浣犲皯鍔?0%鐨勭彮锛?/p>

本文由嘻道妙招独家原创,未经允许,严禁转载