描述cookie和localStorage和sessionStorage的區(qū)別
從容量和API易用性角度社裆。
cookie
-
cookie
本身用于瀏覽器和server
通訊,被“借用”到本地存儲(chǔ) - api為
document.cookie
境钟,不夠友好 - 容量最大為4kB
- http請求時(shí)需要一同發(fā)送到服務(wù)器,增加了請求的數(shù)據(jù)量
localStorage和sessionStorage
- 專為本地存儲(chǔ)而設(shè)計(jì)的,最大為5MB
- API簡單易用,
setItem
布蔗,getItem
- 不會(huì)隨http請求發(fā)送出去
- localStorage數(shù)據(jù)永久存儲(chǔ),除非被動(dòng)刪除
- sessionStorage中存在當(dāng)前會(huì)話浪腐,瀏覽器關(guān)閉后就會(huì)清空
從輸入U(xiǎn)RL到渲染出頁面的整個(gè)過程
- DNS解析:域名 -> IP地址
- 瀏覽器根據(jù)IP地址向服務(wù)器發(fā)送http請求
- 服務(wù)器處理http請求纵揍,并返回給瀏覽器
- 根據(jù)html代碼生成DOM樹
- 根據(jù)CSS代碼生成CSSOM
- 將DOM樹和CSSOM整合成RenderTree
- 根據(jù)RenderTree渲染頁面,遇到
script
標(biāo)簽則暫停渲染议街,優(yōu)先加載腳本并執(zhí)行js代碼泽谨,完成后再繼續(xù)。暫停是因?yàn)镴S進(jìn)程和渲染進(jìn)程是公用一個(gè)線程的,js可能會(huì)改變DOM結(jié)構(gòu) - 直到渲染完成
其中l(wèi)ink要放在head中吧雹,因?yàn)榉旁诤竺婵赡軙?huì)造成再次渲染問題骨杂,js放在最后,是因?yàn)镴S進(jìn)程和渲染進(jìn)程是公用一個(gè)線程的雄卷,而且有可能js加載時(shí)間很長搓蚪,然后就會(huì)造成頁面卡頓現(xiàn)象,img標(biāo)簽不會(huì)暫停渲染丁鹉,不會(huì)阻塞DOM渲染妒潭,不會(huì)造成重排現(xiàn)象。
window.onload和DOMContentLoaded的區(qū)別
window.addEventListener('load', function() {
// 頁面全部資源加載完才會(huì)執(zhí)行揣钦,包括圖片杜耙、視頻
console.log('load'); // 后輸出
})
document.addEventListener('DOMContentLoaded', function() {
// DOM渲染完成即可執(zhí)行,此時(shí)圖片拂盯、視頻可能還未加載完成
console.log('DOMContentLoaded'); // 先輸出佑女,所以操作 js 最好在這個(gè)方法里面
})
性能優(yōu)化
原則:
- 多使用內(nèi)存、緩存
- 減少CPU計(jì)算谈竿,減少網(wǎng)絡(luò)加載耗時(shí)
- 以空間換取時(shí)間
從何入手
1. 讓加載更快
1.1 減少資源的體積:壓縮代碼
1.2 減少訪問次數(shù):合并代碼团驱、SSR渲染、緩存
1.3 使用更快的網(wǎng)絡(luò)
2. 讓渲染更快
2.1 css放在head部分空凸,js放在body最后
2.2 盡早執(zhí)行js嚎花,用DOMContentLoaded觸發(fā)
2.3 懶加載:圖片懶加載、上滑加載更多
2.4 對DOM查詢緩存
2.5 頻繁DOM操作呀洲,合并到一起插入DOM結(jié)構(gòu)
2.6 節(jié)流和防抖
防抖debounce
場景:監(jiān)聽一個(gè)輸入框的文字紊选,變化后觸發(fā)change事件,直接用keyup事件道逗,則會(huì)頻繁觸發(fā)change事件兵罢,使用防抖,只有在用戶輸入結(jié)束或暫停的時(shí)候滓窍,才會(huì)觸發(fā)change事件
<input type="text" id="input1" />
<script>
function debounce(fn, delay = 300) {
let timer = null;
return function() {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.call(this, arguments[0]);
timer = null;
}, delay);
};
}
const input = document.getElementById("input1");
input.addEventListener(
"keyup",
debounce(function(e) {
console.log(this.value, e);
})
);
</script>
節(jié)流throttle
場景:拖拽一個(gè)元素師卖词,要隨時(shí)拿到該元素的拖拽位置,直接用drag事件吏夯,則會(huì)頻繁觸發(fā)此蜈,很容易造成卡頓,此時(shí)使用節(jié)流的話噪生,無論拖拽速度多快裆赵,都快每隔一段時(shí)間觸發(fā)一次
<div
id="div1"
draggable="true"
style="width: 200px;height: 100px;background: rebeccapurple;"
/>
<script>
function throttle(fn, delay = 100) {
let timer = null;
return function() {
if (timer) { // timer不為空就什么都不做
return;
}
timer = setTimeout(() => {
fn.call(this, arguments[0]);
timer = null;
}, delay);
};
}
const div = document.getElementById("div1");
div.addEventListener(
"drag",
throttle(function(e) {
console.log(e.offsetX, e.offsetY);
})
);
</script>
如何捕獲異常
try...catch
window.onerror = funtion(message, source, lineNumber, colNumber, error) {}
var 和let、const的區(qū)別
- var是ES5語法跺嗽,let和const是ES6語法战授,var有變量提升
- var和let是變量舔庶,可修改,const是常量陈醒,不可改變
- let和const有塊級(jí)作用域惕橙,var沒有
手寫一個(gè)深度比較
// 判斷是否是對象
function isObject(target) {
return typeof target === "object" && target !== null;
}
function isEqual(source, target) {
// 只要其中有一個(gè)不是對象,那就直接比較
// 如 isEqual(1, { a: 2 })
// 如 isEqual(1, 1)
if (!isObject(source) || !isObject(target)) {
return source === target;
}
// 如過兩個(gè)都引用的是一個(gè)對象钉跷,直接比較
// 如 isEqual(a, a)
if (source === target) {
return true;
}
// 兩個(gè)都是對象或數(shù)組弥鹦,而且不相等
// 1. 先取出 source 和 target 的keys, 比較個(gè)數(shù)
const sourceKeys = Object.keys(source);
const targetKeys = Object.keys(target);
if (sourceKeys.length !== targetKeys.length) {
return false;
}
// 以 source 為基準(zhǔn)爷辙,和 target 依次遞歸比較
for (let key in sourceKeys) {
const res = isEqual(source[key], target[key]);
// 如果 res 中有一個(gè)為false彬坏,那就直接返回false
if (!res) {
return false;
}
}
// 如果res都為true
return true;
}
const a = { a: 1, b: 2, c: { x: 3, y: 4 } };
const b = { a: 1, b: 2, c: { x: 3, y: 4 } };
const c = { a: 1, b: 2, c: { x: 3, y: 4 }, d: 5 };
const d = { a: 1, b: 2, c: { x: 3, y: 44 } };
console.log(isEqual("aa", "aa")); // true
console.log(isEqual(11, 1)); // false
console.log(isEqual(a, b)); // true
console.log(isEqual(a, c)); // false
console.log(isEqual(a, d)); // false
獲取URL參數(shù)
// 傳統(tǒng)方法
function getURLQueryParams(_url) {
const params = {};
const url = _url || location.href; // _url 存在則用 _url, 不存在則用location.href
const search = url.split("?");
if (!search[1]) {
return params;
}
const searches = search[1].split("&");
searches.map(item => {
const items = item.split("=");
params[items[0]] = items[1];
});
return params;
}
console.log(getURLQueryParams("http:www.baidu.com?name=xxx&age=20")); // {name: "xxx", age: "20"}