typeof原理
JS底層存儲變量會在機器碼低位1-3位存儲類型信息,typeof也是據此判斷的,巧合的是null和object的這三位都是000,因此typeof null == typeof {} == ‘object’。
Chrome80對SameSite的使用
之前寫過Chrome80更新,很重要的一點改動就是對sameSite的改動,之前samesite默認是使用none的,Chrome80之後,這個默認值改爲了lax(寬鬆),也就是說,之前設置爲None時,無論是否跨站,默認請求都會攜帶cookie,但是修改之後,跨站是不會攜帶cookie的。
跨站與同源(跨域)不同,只需要判斷頂級域名和二級域名,如http://a.t.com和https://b.t.com,我們可以認爲它是同站。而設置爲Lax之後,除去get 方法提交表單況或者a 標籤發送 get 請求之外,很多跨站方式並不會攜帶請求。
Promise封裝Ajax
之前被問道一次,也沒讓寫,這裏貼出來:
function Ajax(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.responseType = "JSON";
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && /^[23]\d{2}$/.test(xhr.status)) {
let res = xhr.responseText;
resolve(JSON.parse(res));
}
};
xhr.onerror = function(err) {
reject(err);
};
xhr.send();
});
}
很可能會忘了parse,那樣的出來的是字符串。
JSONP
原理很簡單,利用了script便籤不受同源協定的約束,把要返回的值序列化放到callback後面拼成一個立函數執行形式,然後在客戶端window對象添加一個對應的函數,在這兒函數種對服務端返回的響應包裹的數據進行處理:
function jsonp({url,params,callback}){
return new Promise((resolve, reject) => {
let script = document.body.createElement('script')
params = JSON.parse(JSON.stringify(params))
let arr = []
for(let key in params){
arr.push(`${key}=${params[key]}`)
}
arr.push(`callback=${callback}`)
script.src = `${url}?${arr.join("&")}`;
document.appendChild(script)
window[callback]=function(data){
if(!data) reject('failed')
resolve(data)
document.body.removeChild(script)
}
})
}
簡單認識websocket
之前對webSocket的簡單瞭解就是實現了服務器主動推送,畢竟在此之前,我們實現推送都是通過輪詢的方式實現的。
首先,WebSocket建立在 TCP 協議之上,與 HTTP 協議有着良好的兼容性。默認端口也是80和443,並且握手階段採用 HTTP協議,同時它的數據格式比較輕量,性能開銷小,通信高效。可以發送文本,也可以發送二進制數據。
還有一點它不受沒有同源限制,客戶端可以與任意服務器通信。協議標識符是ws(如果加密,則爲wss),服務器網址就是 URL。
HTTP握手後,WebSocket基於HTTP協議進行升級,服務端返回101狀態碼標識協議切換,後序的數據交互都按照新的協議進行。建立連接後,後續的操作都是基於數據幀的傳遞。
兩種解決Effect錯誤依賴的方法
看個Demo:
export default function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
console.log("in");
setCount(count + 1);
}, 1000);
return () => {
console.log("out");
clearInterval(id);
};
}, []);
return <h1>{count}</h1>;
}
這裏,我們依賴爲空,只會渲染一次,setInterval導致"in"每隔1秒會輸出,而UseEffect並不會重複執行,因此每次我們的count爲0,+1,返回的總是1。
解決1:
export default function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
console.log("in");
setCount(count + 1);
}, 1000);
return () => {
console.log("out");
clearInterval(id);
};
}, [count]);
return <h1>{count}</h1>;
}
但是這樣只會使得我們每次都要刪除定時器再添加,不符合我們的需求。
解決2:
export default function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
console.log("in");
setCount(c=c+ 1);
}, 1000);
return () => {
console.log("out");
clearInterval(id);
};
}, []);
return <h1>{count}</h1>;
}
使用函數式更新state是最好的解決方法。
關於函數依賴,我們可以使用三個方式:
- 把函數寫在useEffect種,確保它不依賴組件其他狀態。
- 把函數寫在組件外
- 使用useCallback包裹。