什麼是內存洩露
- 程序的運行需要內存。只要程序提出要求,操作系統或者運行時(runtime)就必須供給內存。
- 對於持續運行的服務進程(daemon),必須及時釋放不再用到的內存。否則,內存佔用越來越高,輕則影響系統性能,重則導致進程崩潰。
- 不再用到的內存,沒有及時釋放,就叫做內存洩漏(memory leak)。
JavaScript 中常見的幾種內存洩露
- 全局變量引起的內存洩漏
function leaks(){
leak = '***'; //leak 成為一個全局變量,不會被回收
}
- 閉包引起的內存洩漏
var leaks = (function(){
var leak = '***';// 被閉包所引用,不會被回收
return function(){
console.log(leak);
}
})()
- dom清空或刪除時,事件未清除導致的內存洩漏
document.querySelector("#demo").addEventListener('click', myFunction);
var para1=document.querySelector("#demo");
para1.parentNode.removeChild(para1);
如果我們在沒有取消 click 方法前去銷燬了 para1 節點,就會造成內存洩露。
正確的做法:
document.querySelector("#demo").addEventListener('click', myFunction);
// 我們需要在刪除節點前清除掛載的 click 方法
document.querySelector("#demo").removeEventListener("click", myFunction);
var para1=document.querySelector("p1");
para1.parentNode.removeChild(para1);
具體的示例
Demo1:
componentWillMount: function () {
var onLogin = this.props.onLogin || function () {},
onLogout = this.props.onLogout || function () {};
this.on('authChange', function () {
console.log('user authenticated:', this.state.isAuthenticated);
return this.state.isAuthenticated
? onLogin(this.state)
: onLogout(this.state);
}.bind(this));
}
上面的例子是在 Stack Overflow 上看到的,樓主在componentWillMount的時候掛載了authChange事件,然後 react 出現瞭如下的報錯:
Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method”
意思為:我們不能在組件銷燬後設置state,防止出現內存洩漏的情況
需要怎麼解決啦?
添加如下代碼即可
componentWillUnmount: function () {
this.off('authChange', this.authChange);
this.authChange = null;
}
很明顯這種情況就是在 dom 結構銷燬的時候,事件卻沒有清除導致的內存洩漏,所以我們需要在componentWillUnmount的時候去清除掛載的方法
react 內存洩露相關解釋和解決方法
這裡就提到了內存洩露,當我們在使用事件綁定,setInterval,setTimeOut 或一些函數的時候,但是卻沒有在組件銷燬前清除的時候會造成內存洩露。這裡我們手動的再componentWillUnmount去清除相關的方法即可。
Demo 2
下面這種就是常見的情況:
this.pwdErrorTimer = setTimeout(() => {
this.setState({
showPwdError:false
})
}, 1000);
設置了一個timer延遲設置state,然而在延遲的這段時間,組件已經銷燬,則造成此類問題
解決方法:
利用生命週期鉤子函數:componentWillUnmount
componentWillUnmount(){
clearTimeout(this.pwdErrorTimer);
clearTimeout(this.userNameErrorTimer);
}
閱讀更多 滬漂程序員的生活史 的文章