『壹』 前端性能優化-處理大批量DOM元素
滾動監聽事件
『貳』 公安網載入dom組件失敗原因
1. 事件失效的原因:
(1)bind事件綁定只對dom中存在的元素有效,對於我們後來動態增加的元素是監測不到,所以綁定不了
(2)同樣,當你使用var aa = document.getElementsByTagName("動態生成的元素");來獲取動態生成的元素的時候也是獲取不到的,因為網頁只會執行一次初始化綁定,之後動態生成的dom元素也是監測不到的。
2. 解決辦法:
(1)在每一個動態生成的地方都再綁定多一次事件,比如這個博客裡面的例子
(2)把bind改用live,因為live是實時監測的,對於新增的dom元素也是有效的(因為不斷去綁定、判斷,所以可能會影響Web性能問題)
(3)把bind改用delegate,因為delegate是實時監測的。
(4)在jquery1.7 起版本用on替代了bind()、live() 和 delegate() 方法。
『叄』 前端錯誤Uncaught TypeError: Cannot read property 'length' of null錯誤怎麼處理
通過統計資料庫中的1000多個項目,我們發現在 JavaScript 中最常出現的錯誤有10個。下面會向大家介紹這些錯誤發生的原因以及如何防止。
1. Uncaught TypeError: Cannot Read Property
這是 JavaScript 開發人員最常遇到的錯誤。當你讀取一個屬性或調用一個未定義對象的方法時,Chrome 中就會報出這樣的錯誤。
導致這個錯誤發生的原因有很多,常見的一種情況是在渲染 UI 組件時,不正確地初始化狀態。我們來看一個真實的應用程序中發生這種情況的例子。
以上代碼有兩個重要方面:
一是組件的狀態(例如 this.state),在開始生命周期之前是 undefined 狀態。
二是當通過非同步的方式獲取數據時,無論是在構造函數中 componentWillMount 中,還是在構造函數中提取 componentDidMount,組件在數據載入之前至少會渲染一次。當檢測首次渲染時,會發現 this.state.items 是未定義的。此時就會出現一個錯誤 -「Uncaught TypeError: Cannot read property 『map』 of undefined" in the consol」。
解決的方法很簡單:在構造函數中使用合理的默認值進行狀態初始化。
2. TypeError: 『undefined』 Is Not an Object (evaluating...)
這是在 Safari 中讀取屬性或調用未定義對象上的方法時發生的錯誤,這與 Chrome 的上述錯誤基本相同,只是 Safari 使用不同的錯誤消息。
3. TypeError: Null Is Not an Object (evaluating...)
這是在 Safari 中讀取屬性或調用空對象上的方法時發生的錯誤。
在實際情況中,導致這種錯誤的原因之一是:在元素載入之前,就嘗試在 JavaScript 中使用 DOM 元素。這是因為 DOM API 對於空白的對象引用返回 null。
任何執行和處理 DOM 元素的 JS 代碼,都應該在創建 DOM 元素之後執行。JS 代碼按照 HTML 中的規定自上而下進行解釋。因此,如果在 DOM 元素之前存在標簽,則腳本標簽內的 JS 代碼就會在瀏覽器分析 HTML 頁面時執行。如果在載入腳本之前尚未創建 DOM 元素,就會出現這樣的錯誤。
在這個例子中,我們可以通過添加一個事件偵聽器來解決這個問題,事件偵聽器會在頁面准備就緒時通知我們。一旦 addEventListener 被觸發,該 init( ) 方法就可以使用 DOM 元素。
4. (unknown): Script Error
當未捕獲的 JavaScript 錯誤違背跨邊界原則時,就會發生腳本錯誤。例如,如果將 JavaScript 代碼託管在 CDN 上,則任何未被捕獲的錯誤(通過 window.onerror 處理程序發出的錯誤,而不是 try-catch 中捕獲到的錯誤)將僅報告為「腳本錯誤」。這是瀏覽器的一種安全措施,主要用於防止跨域傳遞數據的情況出現。
要獲取真實的錯誤消息,需要執行以下操作:
Access-Control-Allow-Origin
將
Access-Control-Allow-Origin 設置為 *, 表示可以從任何域正確訪問資源。* 如有必要,也可以用自己的域名進行替換,例如:
Access-Control-Allow-Origin: www.example.com。
以下是在各種環境中設置的一些示例:
在腳本標簽上設置crossorigin =「anonymous」
在你的 HTML 源代碼中,為每一個腳本設置
Access-Control-Allow-Origin,在設置 SCRIPT 標簽中,設置 crossorigin="anonymous"。在將 crossorigin 屬性添加到腳本標簽之前,請確保正在向腳本文件發送 header。在 Firefox 中,如果 crossorigin 屬性存在但 Access-Control-Allow-Origin 標題不存在,則腳本不會執行。
5. TypeError: Object Doesn』t Support Property
當調用未定義的方法時,IE 中會發生這樣的錯誤。
這相當於 Chrome 中的 「undefined』 is not a function」 錯誤。對於相同的邏輯錯誤,不同的瀏覽器可能會有不同的錯誤消息。
這是在 IE 的 Web 應用程序中使用 JavaScript 命名空間出現的一個常見問題。出現這種情況的絕大部分原因是IE無法將當前名稱空間內的方法綁定到this關鍵字。例如,如果你有 JS Rollbar 方法的命名空間 isAwesome。通常,如果位於 Rollbar 命名空間內,則可以使用以下語法調用該 isAwesome 方法:
6. TypeError: 『undefined』 Is Not a Function
當調用未定義的函數時,Chrome 中就會發生這樣的錯誤。
執行上面的代碼會導致以下錯誤:「Uncaught TypeError: undefined is not a function。」 發生以上錯誤的原因是,當你調用 setTimeout( ) 時,實際上是在調用 window.setTimeout( ),傳遞給 setTimeout( ) 的匿名函數是在窗口對象的上下文中定義的,而該窗口對象沒有 clearBoard( ) 方法。
符合舊版瀏覽器的解決方案是以變數的方式簡單地將引用保存在 this 中,然後通過閉包繼承。
『肆』 JS操作大量Dom數據時,假死現象
1:JS中大量的DOM操作也會導致事件響應緩慢甚至真正卡死瀏覽器,如在IE6下一次插入大量的HTML。而如果真的彈出了「腳本運行時間過長「的提示框則說明你的JS腳本肯定有死循環或者進行過深的遞歸操作了。
2:這時候需要對腳本進行優化,其步驟如下:
第一步,優化循環,循環體中包含太多的操作和循環的次數過多都會導致循環執行時間過長,並直接導致鎖死瀏覽器。如果循環之後沒有其他操作,每次循環只處理一個數值,而且不依賴於上一次循環的結果則可以對循環進行拆解,看下面的chunk的函數:
function chunk(array, process, context){
setTimeout(function(){
var item = array.shift();
process.call(context, item);
if(array.length >0){
setTimeout(arguments.callee,100);
}),100);
}
chunk()函數的用途就是將一個數組分成小塊處理,它接受三個參數:要處理的數組,處理函數以及可選的上下文環境。每次函數都會將數組中第一個對象取出交給process函數處理,如果數組中還有對象沒有被處理則啟動下一個timer,直到數組處理完。這樣可保證腳本不會長時間佔用處理機,使瀏覽器出一個高響應的流暢狀態。
其實看來,藉助JS強大的閉包機制任何循環都是可拆分的,下面的版本增加了callback機制,使可再循環處理完畢之後進行其他的操作。
function chunk(array,process,cbfun){
var i=0,len = array.length; //這里要注意在執行過程中數組最好是不變的
setTimeout(function(){
process( array[i], i++); //循環體要做的操作
if( i < len ){
setTimeout(arguments.callee,100)
}else{
cbfun() //循環結束之後要做的操作
}
}
}
第二步,優化函數,如果函數體內有太多不相干但又要一起執行的操作則可以進行拆分,考慮下面的函數:
function dosomething(){
dosomething1();
dosomething2();
}
dosomething1和dosomething2互不相干,執行沒有先後次序,可用前面提到的chunk函數進行拆分:
function dosomething(){
chunk([dosomething1,dosomething2],function(item){item();})
}
或者直接交給瀏覽器去調度
function dosome(){
setTimeout(dosomething1,0);
setTimeout(dosomething2,0);
}
第三步,優化遞歸操作,函數遞歸雖然簡單直接但是過深的遞歸操作不但影響性能而且稍不注意就會導致瀏覽器彈出腳本失控對話框,必須小心處理。
看以下斐波那契數列的遞歸演算法:
function fibonacci(n){
return n <2? n: fibonacci(n -1)+ fibonacci(n -2);
};
fibonacci(40)這條語句將重復調用自身331160280次,在瀏覽器中執行必然導致腳本失控,而採用下面的演算法則只需要調用40次
fibonacci =function(n){
var memo ={0:0,1:0}; //計算結果緩存
var shell =function(n){
var result = memo[n];
if(typeof result !='number') //如果值沒有被計算則進行計算
memo[n]= shell(n-1)+ shell(n -2)
return memo[n];
}
return shell(n);
}
這項技術被稱為memoization,他的原理很簡單就是同樣的結果沒必要計算兩次。另一種消除遞歸的辦法就是利用迭代,遞歸和迭代經常會被作為互相彌補的方法。
第四步,減少DOM操作,DOM操作的代價是相當昂貴的,大多數DOM操作都會觸發瀏覽器的迴流(reflow)操作。例如添加刪除節點,修改元素樣式,獲取需要經過計算的元素樣式等。我們要做的就是盡量少的觸發迴流操作。
el.style.width ='300px' el.style.height ='300px' el.style.backgroundColor ='red'
上面的操作會觸發瀏覽器的三次迴流操作,再看下面的方式:
el.className ='newStyle'
通過設置改元素的className一次設置多個樣式屬性,將樣式寫再CSS文件中,只觸發一次迴流,達到了同樣是效果而且效率更高。因為瀏覽器最擅長的就是根據class設置樣式。
還有很多可以減少DOM操作的方法,在此就不多說了,但是一個基本的原則就是讓瀏覽器去做它自己擅長的事情,例如通過class來改變元素的屬性。
相信經過上面的優化的過程必定可以大大提高用戶體驗,不會出現瀏覽器被鎖死和彈出腳本失控的對話框,使你的瀏覽器從繁重的任務中解放出來。需要指出的是上面這些優化並不是必須的,只有當一段腳本的執行時間真的影響到了用戶體驗才需要進行。雖然讓用戶覺得腳本的執行變快了,但其實完成同一個操作的時間可能被延長了,這些技術只是讓瀏覽器處於一個快速響應的狀態,使瀏覽更流暢。
『伍』 解決vue頁面DOM操作不生效的問題
現象:
使用Element
UI渲染了一個樹形結構,設計在滑鼠移入每個節點是顯示其中的操作按鈕,效果如下:
下面是出錯部分:
在新增節點後移入新增節點附近(圖中是移入一級2),功能按鈕的顯示位置出現偏移
原因查找:
經過調試發現是在新增節點後,執行DOM操作獲取節點時,取到的仍是之前的結構,新增的節點並未獲取到。
原因分析:
猜測是vue使用的虛擬DOM,使得頁面雖然已經渲染出來,但在Vue實例中讓處在在虛擬DOM中,無法獲取。
解決方法:
使用Vue.nextTick,看下官方材料:
『在下次
DOM
更新循環結束之後執行延遲回調',這句話不是特別理解,不過可以看出DOM更新是一個循環的過程,在過程結束之前無法獲取到真實的DOM元素(至於這個循環是多久,還在探索中)。而將DOM操作放在nextTick中操作便可以獲取到更新後的DOM。
結果:
依據上述原理,將DOM操作的函數在更新數據後在nextTick里調用,實現了理想中的效果。
以上這篇解決vue頁面DOM操作不生效的問題就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
您可能感興趣的文章:vue指令以及dom操作詳解
『陸』 頁面中變數存太多變數會卡嗎
不會。
頁面卡頓應該不是全局變數過多造成的,通常會造成這種情況要麼是出現了太密集頻繁的dom元素操作,因為操作dom的開銷是很大的,嚴重的話會阻礙瀏覽器UI引擎的渲染使頁面感覺卡頓,這也是現今虛擬dom能在各種框架流行的原因;要麼就是出現了時間復雜度過大的運算,例如嵌套多次的循環之類的,總之你要排查一下你的代碼有沒有邏輯不合理的地方,然後嘗試去優化它,例如把太耗時的計算放入worker線程中去執行等。