前端性能優化問題?
這個問題無疑是面試常見的問題之一,看了
大神文章以後以爲本身以前的回答好次哦,站的角度不夠高,那麼下邊咱們就來看一下,怎樣回答好這個問題。
-
文件引入位置: css放在head中引入; js放到script末尾引入,防止阻止頁面的加載
-
減小文件體積: 刪除冗餘代碼、 壓縮混淆代碼、 文件按需加載
-
圖片的優化: 在保證分辨率的狀況下儘可能壓縮圖片; 小的圖片能夠採用多張拼成一張雪碧圖,減小圖片請求次數; 低於5k圖片能夠採用base64的圖片格式,不須要發請求,瀏覽器能直接編譯;
-
減小http請求,合併請求
-
合理使用緩存: 能夠將數據存儲到瀏覽器上,合理利用瀏覽器的緩存,避免重複發送請求; 若是使用cdn的話,也可利用cdn緩存;(cdn是什麼?就相似於京東在各地的倉庫,都會從最近的地方查找數據,最快的送到用戶手中)
-
能夠將首屏加載的文件儘量縮小,
-
資源能夠採用懶加載和異步加載的方式,避免堵塞頁面渲染
-
利用瀏覽器提供的preload、prefetch等資源提示,加快文件傳輸。
-
避免對象嵌套的太深,這樣讀取也會緩慢,也不利於數據的維護
-
減小循環次數: 一方面能夠減小循環的數據量的大小,一方面能夠在達到要求的時候儘快結束循環。
-
儘可能避免使用for-in循環,由於他會枚舉原型對象
-
條件判斷的流程性能:Map>switch>if-else
// 使用if-else
if (type === 1) {
} else if (type === 2) {
} else if (type === 3) {
}
// 使用switch
switch (type) {
case 1:
break;
case 2:
break;
default:
break;
}
// 使用Map
const map = new Map([
[1, () => {} ],
[2, () => {} ],
[3, () => {} ],
]);
map.get(type)();複製代碼
5. dom優化: 減小dom的請求,能夠將dom進行緩存; 儘可能減小在js中修改樣式,減小頁面的重繪和迴流; 可使用document.fragment,減小頁面重繪次數;
減小選擇器層級的嵌套; 減小通配符和屬性選擇器的使用; 7. html優化: 減小dom數量,避免沒必要要的嵌套; 避免使用<img src='''/> 空標籤,減小服務器壓力; 提早定義好 圖片的寬高,避免因圖片加載致使的瀏覽器迴流; 儘可能使用語義化標籤,有利於seo和瀏覽器解析時間;
瀏覽器事件循環機制(event-loop)
JS執行是單線程的,可是瀏覽器執行的時候還配合有一個任務隊列;
JS是從上到下執行代碼的,當發生一個任務,判斷是同步任務仍是異步任務: 若是是同步任務,把該任務放到主線程執行,若是是異步任務放到任務隊列執行;
宏任務:script, setTimeOut, setInterval
微任務:Promise.then(),process.nextTick
每次微任務執行完以後,都回去微任務隊列裏去檢查,若是微任務中有操做,就執行微任務的操做,執行完以後再次執行下一個宏任務,一次循環;
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})複製代碼
第一次執行宏任務是,遇到console.log 因此打印了2;
遇到setTimeout,把setTimeout的回調放到宏任務中,爲setTimeout1;
遇到process.next,把process.next的回調放到微任務中,爲process1;
遇到promise時,當即執行console.log('7'),因此打印7,then裏邊的操做爲異步操做,因此將then的回調放到微任務中,爲then1;
遇到下一個setTimeout,把setTimeout的回調放到宏任務中,爲setTimeout2;
此時,打印了2,7。那麼看下此時宏任務和微任務中都有哪些東西
宏任務:setTimeout一、setTimeout2
微任務:process一、then1;複製代碼
此時將執行清空微任務的操做,則執行process一、then1,則依次打印六、8。
下邊將下一個宏任務即set Ti meout1放到執行棧中,即第二次執行宏任務。
遇到console是,遇到console.log 因此打印了2;
遇到process.nextTick,則把其回調放到微任務中,爲process2;
遇到promise,則當即執行console,打印4,並將then放到微任務中,爲then2;
宏任務:setTimeout2
微任務:process二、then2;複製代碼
這樣第二個宏任務執行完畢,接下來清空微任務,則執行process二、then2,依次打印3,5;
接下來將setTimeout2放到執行棧中執行,即第三次宏任務。
遇到console是,遇到console.log 因此打印了9;
遇到process.nextTick,則把其回調放到微任務中,爲process3;
遇到promise,則當即執行console,打印11,並將then放到微任務中,爲then3;
宏任務:
微任務:process三、then3;複製代碼
這樣第三個宏任務執行完畢,接下來清空微任務,則執行process三、then3,依次打印10,12;