防抖和節(jié)流
防抖:
觸發(fā)高頻事件后n秒內(nèi)只執(zhí)行一次,如果n秒內(nèi)再次觸發(fā),則重新計(jì)算時(shí)間,多用于按鈕防止重復(fù)點(diǎn)擊 input輸入校驗(yàn)
實(shí)現(xiàn)方式:每次觸發(fā)事件都取消掉上次的延時(shí)調(diào)用,
節(jié)流:
高頻事件在n秒內(nèi)只執(zhí)行一次,節(jié)流會(huì)稀釋函數(shù)的執(zhí)行頻率.多用于高頻操作,touchmove mousemove input keyup
實(shí)現(xiàn)方式: 每次觸發(fā)的時(shí)候都判斷當(dāng)前是否有等待執(zhí)行的延時(shí)函數(shù)
npm實(shí)現(xiàn)原理
npm script
npm 允許用戶在pakage.json里面用scripts對(duì)象自定義用戶執(zhí)行腳本,npm script對(duì)外提供統(tǒng)一的接口,在運(yùn)行一段腳本時(shí),新建一個(gè)shell,會(huì)將當(dāng)前的node_modules/.bin生成PATH變量, 結(jié)束之后再恢復(fù)PATH變量.
scripts:{
test: mocha test //替代 './node_modules/.bin/mocha test'
}
npm scripts腳本本來(lái)就是shell腳本,可以使用shell的能力--shell通配符,傳參,bash多腳本執(zhí)行順序(&并行執(zhí)行)(&&串行執(zhí)行)
npm 鉤子
npm腳本有pre和post鉤子, 執(zhí)行順序 npm run prebuild && npm run build && npm run postbuild
npm 變量
npm install
執(zhí)行自身的preinstall
宏任務(wù)和微任務(wù)
https://blog.csdn.net/weixin_36852235/article/details/89101233
https://time.geekbang.org/column/article/82764
視頻講解: https://www.youtube.com/watch?v=8aGhZQkoFbQ
當(dāng)拿到一段javascript代碼的時(shí)候,瀏覽器和node會(huì)不斷的傳遞給javascript引擎去執(zhí)行,引擎吧代碼直接順序執(zhí)行,這個(gè)就是宿主發(fā)起的任務(wù),在ES5之后,javascript引入的promise,這樣不用瀏覽器或者node的傳遞,javascript引擎本身也可以發(fā)起任務(wù),所以我們吧瀏覽器或者node發(fā)起的任務(wù)成為宏觀任務(wù),jsvsscript引擎發(fā)起的任務(wù)成為微觀任務(wù)
宏任務(wù) event loop
setTimeout setInterval requestAnimationFrame I/O UIRender
微任務(wù)
process.nextStick() promise(在微觀任務(wù)隊(duì)列最后添加任務(wù)) Object.Observe
setTimeout(()=>{
console.log("d1")
r.then(()=>{
console.log("d2")
})
}, 0);
var r = new Promise(function(resolve, reject){ resolve() });
r.then(() => {
var begin = Date.now();
while(Date.now() - begin < 1000); console.log("c1");
new Promise(function(resolve, reject){ resolve() }).then(() => console.log("c2"))
});

看了視屏之后發(fā)現(xiàn)畫的圖產(chǎn)生了一些誤解:
V8引擎的event loop事件循環(huán),只有webApi產(chǎn)生的回調(diào)都在task queen任務(wù)隊(duì)列里面,
1.當(dāng)前宏任務(wù)產(chǎn)生的微任務(wù)推到微任務(wù)列表,stack執(zhí)行完畢之后,等待..
2.微任務(wù)隊(duì)列把微任務(wù)推到調(diào)用棧執(zhí)行,執(zhí)行完畢,等待...,
3.webapi宏任務(wù),task queen任務(wù)隊(duì)列把回調(diào)推入調(diào)用棧執(zhí)行
瀏覽器的工作原理
http緩存
作用:
1)減少冗余的數(shù)據(jù)傳輸
2)減少服務(wù)器的壓力
3)加快的網(wǎng)頁(yè)的呈現(xiàn)速度
http緩存只響應(yīng)get請(qǐng)求響應(yīng)的資源,瀏覽器先校驗(yàn)強(qiáng)緩存,再次校驗(yàn)協(xié)商緩存
強(qiáng)制緩存
pragma,cache-control:max-age,expire三個(gè)緩存頭字段優(yōu)先級(jí)依次降低,若文件沒(méi)過(guò)期直接從memory cache/disk cache讀取,不進(jìn)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求狀態(tài)200
協(xié)商緩存
etag/if-none-match,last-modified/if-modified-since響應(yīng)頭/請(qǐng)求頭,先去進(jìn)行網(wǎng)絡(luò)請(qǐng)求,服務(wù)器根據(jù)if-none-match(hash值對(duì)比) | if-modified-since(過(guò)期時(shí)間判斷)進(jìn)行文件過(guò)期判斷,沒(méi)過(guò)期則返回304,過(guò)期則返回200且把文件返回
圖片一般緩存在memory cache中,js一般緩存在disk cache中
瀏覽器緩存
cookies
每次和請(qǐng)求都會(huì)帶上當(dāng)前域名下的cookies 可以設(shè)置過(guò)期時(shí)間
localstorage
本地存儲(chǔ),不與后端交互,需要手動(dòng)刪除
sessionstorage
本地存儲(chǔ),不與后端交互,會(huì)話結(jié)束,緩存失效
瀏覽器async和defer (性能優(yōu)化板塊問(wèn)題)
async和defer都是為了優(yōu)化網(wǎng)頁(yè)的加載速度,使得頁(yè)面的空白時(shí)間更短,獲得更好的客戶體驗(yàn)
1)<script src=""></script>, 沒(méi)有defer或者async,瀏覽器會(huì)立即加載并執(zhí)行腳本,阻塞后續(xù)文檔元素的載入.(這里是作用于詞法分析還是語(yǔ)法分析?)
2)<script src="" async></script>,有async標(biāo)記的資源在加載和執(zhí)行的過(guò)程跟后續(xù)文檔元素的解析和渲染并行執(zhí)行,async標(biāo)記由于因?yàn)榧虞d和執(zhí)行都是異步,所以并不能保證腳本的執(zhí)行順序,此類腳本最適用于 監(jiān)控腳本 打點(diǎn)腳本等不影響主流程的腳本加載,若腳本之間有依賴關(guān)系,不可用async
3)<script src="" defer></script>,有deder標(biāo)記的資源加載過(guò)程和后續(xù)文檔元素的解析和渲染并行執(zhí)行, 執(zhí)行過(guò)程在所有的元素解析完成之后,在DOMcontentloaded之前執(zhí)行,defer標(biāo)記能夠保證及時(shí)加載是異步的,但是執(zhí)行的順序是按照文檔的順序執(zhí)行.
對(duì)于實(shí)用的角度來(lái)講,把所有的腳本都丟到<body>標(biāo)簽下加載是最簡(jiǎn)單的一種方法,能夠保證一切非腳本的文檔元素得到最快速的加載和解析
值得注意的是,不管是defer還是async,腳本執(zhí)行過(guò)程都會(huì)阻塞html文檔的解析是因?yàn)閖s能操作DOM,瀏覽器為了避免重新構(gòu)建DOM樹(shù),腳本執(zhí)行進(jìn)程和文檔的解析進(jìn)程之間互斥
利用async我們能做什么
性能優(yōu)化之a(chǎn)sync緩存js資源,緩存到本地,下一頁(yè)加載強(qiáng)制緩存直接從disk cache讀取
<script async="" data-next-page="/p/[slug]" src="https://cdn2.jianshu.io/shakespeare/_next/static/puNPQDWhCvW09zKH9N80j/pages/p/%5Bslug%5D.js"></script>
性能優(yōu)化之<link rel="preload"> js,css,圖片資源預(yù)加載
<link rel="preload" as="script">
<link rel="preload" href="wide.png" as="image" media="(min-width: 601px)">
DOMcontentloaded?
在network網(wǎng)頁(yè)的時(shí)間流程里面 下載資源(finish) -> DOMcontentLoaded -> load
DOMcontentLoaded: 表示html文檔元素解析完成,DOM生成完成,時(shí)間與js的位置,大小,html文檔元素的復(fù)雜度有關(guān)
load:表示加載完成,包含圖片,字體,js,css加載完成,時(shí)間與資源的大小相關(guān)
上個(gè)問(wèn)題由于defer標(biāo)記的資源在DOMcontentLoaded之前執(zhí)行,意味著DOMcontentLoaded的觸發(fā)變成了,html解析完成,有defer標(biāo)記腳本必須等到defer腳本執(zhí)行完成,,無(wú)defer腳本直接等到html解析完成之后便可觸發(fā)
分別對(duì)應(yīng)事件: ready(DOMcontentLoaded完成夠觸發(fā)) -> onload(load完成后觸發(fā))
ready事件可以監(jiān)聽(tīng)多個(gè),不會(huì)沖突和覆蓋,load事件只能執(zhí)行一次,
多次監(jiān)聽(tīng),后面會(huì)覆蓋前面,只執(zhí)行最后一次函數(shù)
文檔解析parse: html文檔->DOM(文檔對(duì)象模型) css->cssOM(css對(duì)象模型)
合并渲染redener: DOM + cssOM
冒泡bubble和捕獲capture?
cdn是什么?
頁(yè)面性能優(yōu)化之預(yù)加載
- <link rel="dns-prefetch">
dns prefetch通過(guò)指定的url告訴瀏覽器未來(lái)會(huì)用到的相關(guān)資源,讓瀏覽器盡早的解析dns
<link rel="dns-prefetch" >
- <link rel="preconnect">
preconnect不僅會(huì)解析dns,還會(huì)建立TCP握手連接和TLS協(xié)議
<link rel="preconnect" >
- <link rel="prefetch">
prefetch可以預(yù)先加載下一個(gè)頁(yè)面或者未來(lái)所需要的文件,緩存在本地
prefetch 是告訴瀏覽器頁(yè)面可能需要的資源,瀏覽器不一定會(huì)加載這些資源(空閑時(shí)間加載)
-
下次加載資源的時(shí)候會(huì)從 prefetch cache讀取
image.png
<link rel="prefetch" href="image.png">
<link rel="prefetch" href="a.js">
- <link rel="prerender">
prerender可以預(yù)先加載下一個(gè)頁(yè)面的所有資源
<link rel="prerender" href="/thenextpage.html"/>
- <link rel="preload">
preload提供一種聲明式的命令,讓瀏覽器提前加載資源(加載后不執(zhí)行),在需要執(zhí)行的時(shí)候再執(zhí)行,有as屬性可以提前知道資源加載的類型
preload和prefetch一樣有預(yù)加載的能力,區(qū)別是: preload 是告訴瀏覽器頁(yè)面必定需要的資源,瀏覽器一定會(huì)加載這些資源;
<link rel="preload" href="a.js" as="script">
async加載js也可以緩存下一頁(yè)的js,但是它會(huì)阻礙window.onload的執(zhí)行,preload則不會(huì)
Preload 的好處
- 加載和執(zhí)行分開(kāi),可不阻塞window.onload事件,在漸近式的程序(單頁(yè)應(yīng)用,動(dòng)態(tài)加載的程序)中,preload會(huì)大大縮短路由到下一頁(yè)面的時(shí)間
- 提前加載指定資源,不再出現(xiàn)依賴的font字體隔了一段時(shí)間才刷出
不能混用prefetch和preload
preload 和 prefetch 混用的話,并不會(huì)復(fù)用資源,而是會(huì)重復(fù)加載,會(huì)帶來(lái)雙倍的網(wǎng)絡(luò)請(qǐng)求
react render原理
render周期:
state,props和render的關(guān)系,只要state和props改變,就重新render,子組件也重新render
render原理:
state數(shù)據(jù)+JSX模板結(jié)合,生成(react.creatElement )新的虛擬DOM樹(shù)(虛擬DOM都是一個(gè)js數(shù)組,完整的描述了當(dāng)前節(jié)點(diǎn)的所有特性),對(duì)比直接生成真實(shí)的DOM(document.creatElement調(diào)用webapi)損耗小很多
,最后根據(jù)虛擬dom生成真實(shí)dom,當(dāng)state和props發(fā)生更改的時(shí)候,生成新的虛擬DOM樹(shù),與老的虛擬DOM樹(shù)diff,產(chǎn)出差異DOM樹(shù),進(jìn)行真是DOM更新
虛擬DOM是什么:
虛擬DOM都是一個(gè)js數(shù)組,完整的描述了當(dāng)前節(jié)點(diǎn)的所有特性
虛擬DOM的優(yōu)點(diǎn):
1.性能提升,使得每次render耗費(fèi)時(shí)間短
2.跨平臺(tái)的方案得以實(shí)現(xiàn),虛擬DOM就是JS數(shù)組,各個(gè)平臺(tái)都是借助虛擬DOM實(shí)現(xiàn)自己的渲染邏輯
diff算法:
傳統(tǒng)的樹(shù)與樹(shù)的比較算法,時(shí)間復(fù)雜度為O(n^3) reactDiff時(shí)間復(fù)雜度可為O(n)
優(yōu)化策略:
策略一(tree diff): DOM節(jié)點(diǎn)中跨層級(jí)的節(jié)點(diǎn)移動(dòng)操作少
策略二(component diff):擁有相同類的兩個(gè)組件 生成相似的樹(shù)形結(jié)構(gòu).
策略三(element diff):對(duì)于同一層級(jí)的一組子節(jié)點(diǎn),通過(guò)唯一id區(qū)分。
實(shí)現(xiàn):
treeDiff: 同層次節(jié)點(diǎn)比較,updateDepth對(duì)虛擬DOM樹(shù)進(jìn)行層次控制,一旦節(jié)點(diǎn)類型不一樣,直接替換
componentDiff: react基于組件式開(kāi)發(fā),同類型組件繼續(xù)比較treeDiff,不同類型直接替換
elementDiff: 以key值進(jìn)行標(biāo)記,同層級(jí)節(jié)點(diǎn)提供三種方式: insert move remove
得到最后的 patches對(duì)象,進(jìn)行必要的webapiDOM操作
TCP/IP協(xié)議
tcp/ip協(xié)議是網(wǎng)絡(luò)傳輸層的協(xié)議,為應(yīng)用層提供報(bào)文傳輸服務(wù).
TCP場(chǎng)景
- 需鏈接,可靠傳輸應(yīng)用,文件傳輸,HTTP,HTTPS.FTP等
UDP
- 無(wú)連接,實(shí)時(shí)傳輸,視屏?xí)h,直播等
TCP鏈接實(shí)質(zhì)是客戶端和服務(wù)端保存一份關(guān)于對(duì)方的信息,如,ip 端口號(hào)等
三次握手
三次握手的實(shí)質(zhì)是客戶端和服務(wù)端確認(rèn)對(duì)象收/發(fā)數(shù)據(jù)的能力
- 第一次: 客戶端->服務(wù)端 發(fā)送傳輸請(qǐng)求[標(biāo)志位SYN=1,隨機(jī)序列號(hào)seq=100]
- 第二次:服務(wù)端->客戶端 同意傳輸請(qǐng)求[標(biāo)志位SYN=1 ACK=1,隨機(jī)序列號(hào)seq=500,確認(rèn)號(hào)ack=101]
- 第三次: 客戶端->服務(wù)端 確認(rèn)信息[標(biāo)志位ACK=1,序列號(hào)seq=101,確認(rèn)號(hào)ack=501]
連接建立完畢,可以開(kāi)始傳輸報(bào)文
為什么是三次不是2次
2次握手,客戶端不知道服務(wù)端已經(jīng)ready,就不會(huì)發(fā)送報(bào)文,服務(wù)端白白浪費(fèi)資源
客戶端故障怎么處理
TCP有連接保活,計(jì)時(shí)器2小時(shí)沒(méi)報(bào)文傳輸,發(fā)送探測(cè)報(bào)文,10次無(wú)響應(yīng)則關(guān)閉連接
四次揮手
- 第一次:客戶端->服務(wù)端 發(fā)送關(guān)閉請(qǐng)求[標(biāo)志位FIN=1,隨機(jī)序列號(hào)seq=100] (此時(shí)不再發(fā)送數(shù)據(jù))
- 第二次:服務(wù)端->客戶端 同意關(guān)閉請(qǐng)求[標(biāo)志位ACK=1,隨機(jī)序列號(hào)seq=500,確認(rèn)號(hào)ack=101] (此時(shí)服務(wù)端處于關(guān)閉等待狀態(tài),仍然可以發(fā)送數(shù)據(jù),)
[數(shù)據(jù)發(fā)送完畢] - 第三次: 服務(wù)端->客戶端 發(fā)送釋放資源請(qǐng)求[標(biāo)志位FIN=1ACK=1,隨機(jī)序列號(hào)seq=1000,確認(rèn)號(hào)ack=101]
- 第四次: 客戶端->服務(wù)端 同意釋放[ACK=1,序列號(hào)seq=101,確認(rèn)號(hào)ack=1001] (此時(shí)服務(wù)端立即釋放資源,客戶端等待關(guān)閉)
[等待一段時(shí)間,關(guān)閉連接]
