css的重繪與回流
重繪:當節點需要更改外觀而不會影響布局。
回流:DOM結構的修改引發DOM幾何尺寸變化的時候,發生回流。
常見的幾何屬性有width、height、padding、margin、left、top、border 或者是DOM節點發生增減移動。
減少重繪和回流的辦法。
使用css3新增屬性:translate替代top等方向值。
避免頻繁使用style,而是采用class。
箭頭函數和普通函數的區別是什么?
普通函數this:
- this總是代表它的直接調用者。
- 在默認情況下,沒找到直接調用者,this指的是window。
- 在嚴格模式下,沒有直接調用者的函數中的this是undefined。
- 使用call,apply,bind綁定,this指的是綁定的對象。
箭頭函數this:
- 在使用=>定義函數的時候,this的指向是 定義時所在的對象,而不是使用時所在的對象;
- 不能夠用作構造函數,這就是說,不能夠使用new命令,否則就會拋出一個錯誤;
- 不能夠使用 arguments 對象;
- 不能使用 yield 命令;
講一下let、var、const的區別
- var 沒有塊級作用域,支持變量提升。
- let 有塊級作用域,不支持變量提升。不允許重復聲明,暫存性死區。不能通過window.變量名進行訪問.
- const 有塊級作用域,不支持變量提升,不允許重復聲明,暫存性死區。聲明一個變量一旦聲明就不能改變,改變報錯。
實現一個new的偽代碼
- 創建一個對象
- 連接原型
- 綁定this
- 返回該對象
function _new(){
let obj = new Object();
let Con = [].shift.call(arguments);
obj.__proto__ = Con.prototype;
let result = Con.apply(obj,arguments);
return typeof result === 'object' ? result : obj
}
原型、原型鏈
原型鏈:每個被實例對象都有__proto__
對象,它指向了構造該對象的構造函數的prototype
屬性。同時該對象可以通過__proto__
對象來尋找不屬于自身的屬性,
原型:就是實現繼承過程中產生的一個概念。
繼承
原理是:復制父類的屬性和方法來重寫子類的原型對象
- 原型繼承
- 構造函數繼承
- 組合繼承
- 寄生繼承
- 寄生組合繼承
- class
- 等等
// 寄生組合繼承方法
function Father(...arr) {
this.some = '父類屬性';
this.params = arr;
}
Father.prototype.someFn = function() {
console.log(1);
}
Father.prototype.someValue = '2';
function Son() {
Father.call(this, 'xxxx');
this.text = '2222';
}
Son.protptype = Object.create(Father.prototype);
Son.prototype.constructor = Son;
Object,create做了什么
Object._create = function(obj){
function F(){}; // 創建了一個新的構造函數F
F.prototype = obj; // 然后將構造函數F的原型指向了參數對象obj
return new F(); // 返回構造函數F的實例對象,從而實現了該實例繼承obj的屬性。
}
閉包
閉包就是有權訪問一個函數內部變量的函數,也就是常說的函數內部嵌套函數,內部函數訪問外部函數變量,從而導致垃圾回收機制沒有將當前變量回收掉。這樣的操作,有可能會帶來內存泄漏。好處就是可以設計私有的方法和變量。
垃圾回收機制(閉包的延伸)
js擁有特殊的垃圾回收機制,當一個變量在內存中失去引用,js會通過特殊的算法將其回收,并釋放內存。
分為以下兩個階段:
- 標記階段:垃圾回收器,從根對象開始遍歷,訪問到的每一個對象都會被標示為可到達對象。
- 清除階段:垃圾回收器在對內存當中進行線性遍歷,如果發現該對象沒有被標記為可到達對象,那么就會被垃圾回收機制回收。
這里面牽扯到了引用計數法,每次引用都被會‘?1’ 如果標記清零,那么就會被回收掉。
簡述深淺拷貝
淺拷貝
通常需要拷貝的對象內部只有一層的這種對象。
常用的方法
-
Object.assign
方法來實現 - 擴展運算符
...obj
深拷貝
通常是嵌套二層或以上的復雜對象
常用方法
-
JSON.parse(JSON.stringfy(object))
; 該方法忽略掉undefined、忽略Symbol、忽略function。只適合簡單深拷貝 - 手寫遞歸方法去實現。
- 通過第三方庫提供的深拷貝實現。
函數的節流和防抖
防抖函數:將多次觸發變成最后一次觸發;
function debounce(fn,wait){
let timer = null;
return function (){
let arg = arguments;
if(timer){
clearTimeout(timer);
timer = null;
}
timer = setTimeout(()=>{
fn.apply(this,arg)
},wait)
}
}
function clg(){
console.log('clg')
}
window.addEventListener('resize',debounce(clg,1000))
節流函數:將多次執行變成每隔一個時間節點去執行的函數
function throttle(fn,time){
let lastTime = null;
return function(){
let nowTime = Date.now();
if(nowTime - lastTime > time || !lastTime){
fn();
last = nowTime
}
}
}
function sayHi(){
console.log('hi')
}
setInterval(throttle(sayHi,1000),500)
call、apply區別
相同點:都是重定向this指針的方法。
不同點:call和apply的第二個參數不相同,call是若干個參數的列表。apply是一個數組
手寫一個call方法
// 在這之前需要重新認識一下call方法的執行操作
let mock = { value : 1 };
function mockNum(){
console.log('value',this.value)
}
mockNum.call(mock) // 改變了函數中this的指向,當前this指向了mock對象
轉換一下實現方法就是
let mock = {
value:1;
mockNum:function(){
console.log('value',this.value)
}
}
mock.mockNum();
所以經過上面這個操作的演化而來的結果就是如下步驟:
1. 將函數設為一個對象的屬性
2. 并將這個函數的屬性調用
3. 刪除該函數
Function.prototype.Mycall = function(context){
let obj = context || window;
obj.fn = this; // 這一步可以看做是this其實就指的當前函數。
let args = [...arguments].slice(1); // 返回刪除第一個元素的數組;
let result = obj.fn(...args); // 調用函數
delete obj.fn;
return result;
}
// 操作一下
let mock = { value : 1 };
function mockNum(){
console.log('value',this.value);
}
mockNum.Mycall(mock) // value 1
然后根據上面的方法再手寫一個apply方法
Function.prototype.Myapply = function (context){
let obj = context || window;
obj.fn = this;
let result = arguments[1] ? obj.fn(arguments[1]) : obj.fn([]);
delete obj.fn;
return result;
}
let mock3 = {
arr: [1, 2, 3, 4, 5],
};
function arrx2(arr) {
return this.arr.concat(arr).map((x) => x * 2);
}
console.log("arrx2", arrx2.myApply(mock3));
bind
bind方法是直接返回一個新的函數,需要手動去調用才能執行。
- 創建一個新函數,當這個新函數被調用時,bind()方法的第一個參數將作為運行他的this,之后的一系列參數將會在傳遞的實參傳入作為他的參數;
特點:1. 返回一個函數。 2. 可以傳入參數;
手寫一個bind方法
例如:
let foo = { value : 1 };
function bar() {
console.log('bindFoo',this.value);
// return this.value // 考慮到函數可能有返回值
}
let bindFoo = bar.bind(foo);
bindFoo() // 1 // 如果有返回值的情況下 bindFoo() === 1;
Function.prototype.Mybind = function(obj){
if(typeof this !== 'function') throw new Error('not a function');
let self = this;
let args = [...arguments].clice(1);
return function F(){
if(this instanceof F){
return new self(...args,...arguments);
}
return self.apply(obj,args.concat([...arguments]));
}
}
關于函數的調用
- 作為一個正常的函數調用
- 函數作為方法調用
- 使用構造函數調用函數
- 作為函數方法調用函數
捕獲和冒泡
捕獲:就是從根元素開始向目標元素遞進的一個關系;從上而下
冒泡:是從目標元素開始向根元素冒泡的過程;想象一下水里的泡泡從下而上。
??stopPropagation 通常理解它是用來阻止事件冒泡的,其實該函數也可以阻止捕獲事件。
簡單介紹一下event loop
js作為單線程語言。在執行過程中,會產生執行環境。這些執行環境中的代碼被順序的加入到執行棧中,如果遇到異步代碼,會被掛起并加入到任務隊列當中,等到主線程任務執行完畢,event loop就會從任務隊列取出需要執行的代碼放入到執行棧中執行。所以本質上來講,js中的異步還是同步的行為。
任務隊列有分為宏任務和微任務隊列。
一次正確的event loop執行順序如下:
- 執行所有同步代碼
- 執行棧為空,查詢是否有需要執行的微任務。
- 微任務(有:則執行,無:則跳出)
- 必要的話開始渲染UI
- 開始下一輪的任務隊列執行宏任務中的異步代碼。
instanceof原理
instanceOf用來判斷右邊的prototype是否在左邊的原型鏈上,告訴我們左邊是否是右邊的實例。
function instanceof(left, right) {
// 獲得類型的原型
let prototype = right.prototype
// 獲得對象的原型
left = left.__proto__
// 判斷對象的類型是否等于類型的原型
while (true) {
if (left === null){
return false
}
if (prototype === left){
return true
}
left = left.__proto__
}
}
typeof
typeof 檢測對象,除開函數是function類型之外。像常見的數組,對象或者是正則,日期等等都是object;
需要注意一下:
typeof Symbol() // 'symbol'
typeof null // object
typeof undefined // undefined
typeof null
檢測輸出object
因為js最初版本,使用的是32位系統,類型的標簽存儲在每個單元的低位中000是object
類型。null
全是0,所以當我們使用typeof進行檢測的時候js錯誤的判斷位object
簡述cookie、localstorage、seesionstorage
名稱 | 大小 | 網絡請求 | 生命周期 |
---|---|---|---|
cookie | 4kb左右 | 每次都會攜帶在HTTP頭中,如果使用cookie保存過多數據會帶來性能問題 | 默認是關閉瀏覽器后失效, 但是也可以設置過期時間 |
localstorage | 5M | 僅在瀏覽器中保存,不參與和服務器的通信 | 除非手動被清除,否則永久保存 |
SessionStorage | 5M | 僅在瀏覽器中保存,不參與和服務器的通信 | 僅在當前會話(窗口)下有效,關閉窗口或瀏覽器后被清除, 不能設置過期時間 |
js跨域如何解決
目前暫時已知的跨域方法是:
- jsonp跨域,原理:script標簽沒有跨域限制的漏洞實現的一種跨域方法,只支持get請求。安全問題會受到威脅。
- cors跨域,通過后端服務器實現,
Access-Control-Allow-Origin
。 - postMessage
window
的一個屬性方法。 - websocket
- nginx反向代理
- iframe跨域
webpack proxy跨域
首先需要明白webpack proxy跨域只能用作與開發階段,臨時解決本地請求服務器產生的跨域問題。并不適合線上環境。配置在webpack的devServer屬性中。webpack中的devsever配置后,打包階段在本地臨時生成了一個node服務器,瀏覽器請求服務器相當于請求本地服務。
深度優先和廣度優先
廣度優先:嘗試訪問盡可能靠近它的目標節點,然后逐層向下遍歷,直至最遠的節點層級。
深度優先:從起始節點開始,一直向下找到最后一個節點,然后返回,又繼續下一條路徑。知道找遍所有的節點。
瀏覽器禁用cookie該如何處理
一般會用到url重寫的技術來進行會話跟蹤,每一次的交互,都會在url后面加上sid=xxx類似的參數。服務端根據這種方式來識別用戶。
commonjs與es6的modules的區別
commonjs | modules |
---|---|
運行時加載 | 編譯時輸出接口 |
輸出的是值拷貝 | 值的引用 |
倒入模塊的路徑可以是表達式 | 字符串 |
this指向當前模塊 | undefined |
Common、AMD、CMD區別
common | AMD | CMD |
---|---|---|
同步 | 異步 | 異步 |
依賴前置 | 就近依賴 |
setTimeout與setInterval的區別
setTimeout表示間隔一段時間之后執行一次調用,而setInterval是每隔一段時間循環調用,直至清除。
內存方面,setTimeout只需要進入一次宏隊列,setInterval不計算代碼執行時間,有可能多次執行多次代碼
解釋一下requestAnimationFrame
- 瀏覽器專門為DOM動畫,canvas動畫,SVG動畫等等有一個統一的刷新機制。
- 按幀對網頁進行重繪。該方法告訴瀏覽器希望執行動畫并請求瀏覽器在下一次重繪之前調用回調函數來更新動畫,
- 由系統來決定回調函數的執行時機,在運行時瀏覽器會自動優化方法的調用。
script標簽如何實現異步加載
- defer:等到整個頁面在內存中華正常渲染結束(DOM結構完全生成,以及其他腳本執行完成),才會執行;
- async是一旦下載完成,渲染就會中斷,執行這個腳本之后,再繼續渲染。
總結就是:defer是渲染完在執行。async是下載完就執行。
另外值得注意的就是:deger腳本會按照在頁面出現的順序加載,而async是不能保證加載順序的。
proxy和defineProperty區別
Object.defineProperty缺點:
- 無法監控數組下標的變化,導致直接通過數組的下標給數組設置值。不能事實響應。vue內部通過數組的一些方法來監聽。
- 只能劫持對象的屬性,因此要對每個對象的屬性進行遍歷。 vue2.x版本之后是通過遞歸和遍歷實現對data對象的數據監控。
proxy:
- 可以劫持整個對象,并返回一個新的對象
- 有多種劫持操作
MVC、MVVM區別
react與vue的區別
- vue使用的是template模版編寫。react使用的是jsx語法。
- 狀態管理:react中的狀態全部存入state中,通常修改的時候需要用到setState方法來更新狀態。 vue中的state對象不是必須,vue是通過data屬性在vue對象中進行管理
- 監聽數據的變化,vue劫持一些函數,能精確的知道數據變化。react中默認是通過比較引用的方式去進行,如果不優化使用shouldComponentUpdate/PureComponent方法優化,那會導致大量的虛擬dom重新渲染
- 數據流不同:vue可以進行組件與dom之間v-modle雙向綁定。react從始至終都只有單向數據流
- vue中使用的是mixins。react使用的是Hoc高階組件
DNS是如何解析的?如何優化
瀏覽器緩存 -> 本地緩存-> hosts文件 -> 路由器緩存 -> ISP DNS緩存 -> DNS遞歸查詢
強緩存和協商緩存
強緩存和協商緩存。強緩存通過響應頭實現:expires和cache-control。它表示在緩存期間不需要在發起請求。協商緩存:如果緩存過期,可以使用協商緩存解決問題。
協商緩存是需要發起請求。協商緩存需要客戶端和服務端共同實現。
html5的離線存儲技術
html5的離線存儲技術,是基于一個新建的.appcache文件的緩存機制(并不是存儲技術)。通過這個文件上的解析清單離線存儲資源,這些資源就會想cookie一樣被存下來。之后網絡處于離線狀態時,瀏覽器會通過被離線存儲的數據進行頁面展示。
link和import區別
link | import |
---|---|
頁面被加載,link會同時被加載 | @import引用的css會等到頁面被加載完成之后再加載。 |
只適用與2.1之后的版本 | link是沒有任何兼容問題的。 |
支持使用js去控制dom改變樣式 | 不支持 |
只能加載css |
get和post請求的區別
get | post |
---|---|
參數長度有限制 | 參數長度無限制 |
get會把請求的數據附加在url上 | post請求會把數據附加在請求體中 |
get是明文傳輸 | post不是明文傳輸 |
請求能緩存 | 不能緩存 |
http和https區別
http | https |
---|---|
80端口 | 443端口 |
無需申請證書 | 需要申請證書 |
超文本傳輸協議 | ssl加密協議 |
快 | 慢(因為會有一個ssl包需要傳輸) |
ssl加密
分為對稱和非對稱加密
- 對稱加密。 客戶端和服務端公用一個密鑰對消息加解密。(客戶端和服務端約定好一個加密鑰匙。客戶端在發消息淺用該密匙對消息加密,發送給服務器,服務器在用該密匙進行解密拿到消息)
- 非對稱加密。客戶端和服務端都有公鑰和私鑰。公鑰加密的內容只有對應的私鑰解密。私鑰自己留著,公鑰發給對方。這樣發送消息之前,對方的公鑰對消息進行加密,受到后在用自己的私鑰進行解密。
setState同步和異步
- setState只是在合成事件和生命周期函數中是異步更新
- 在settimeout、原生事件、async函數中是同步更新。
react請求與生命周期
reac的異步請求,放入componentDidMount中才是正確操作。
因為WillMount中請求發送,react的執行機制是不會等到數據返回之后才繼續往下執行,而是繼續向下執行并render。不會‘暫停’以等待數據到達。
問題:服務器渲染時,如果在WillMount中請求數據,fetch data會執行兩次,一次在服務端一次在客戶端。造成了多余的請求,而且在16版本之后,WillMount可能在一次渲染中多次調用。
通信
- 父傳子:父組件通過props的方式傳遞。
- 子傳父:props+回調函數方式。
- 兄弟組件:找到這兩個共同的父節點,結合props和回調函數進行通信
- 跨層級通信:context通信
- store
React的渲染原理
- 單項數據流,只能通過數據層的變化去影響視圖層變化。
- 數據驅動視圖。無需關注dom,只用關注數據即可
- 渲染過程,生命周期函數
- diff算法。對照兩次dom不同的部分渲染
useEffect和useLayoutEffect區別
useEffect是異步的,useLayoutEffect是同步的
react中的key的作用
key是給每一個虛擬節點的唯一id,可以依靠key,更準確, 更快的拿到oldVnode中對應的vnode節點,利用key的唯一性生成map對象來獲取對應節點,比遍歷方式更快。
react有哪些組件
- 無狀態組件
- 函數或無狀態組件是一個純函數,它可接受接受參數,并返回react元素。這些都是沒有任何副作用的純函數。這些組件沒有狀態或生命周期方法。
- 有狀態組件
- 類或有狀態組件具有狀態和生命周期方可能通過setState()方法更改組件的狀態。類組件是通過擴展React創建的。它在構造函數中初始化,也可能有子組件。
- 受控組件
- 受控組件是在 React 中處理輸入表單的一種技術。表單元素通常維護它們自己的狀態,而react則在組件的狀態屬性中維護狀態。我們可以將兩者結合起來控制輸入表單。這稱為受控組件。因此,在受控組件表單中,數據由React組件處理。
4 非受控組件 - 大多數情況下,建議使用受控組件。有一種稱為非受控組件的方法可以通過使用Ref來處理表單數據。在非受控組件中,Ref用于直接從DOM訪問表單值,而不是事件處理程序。
5 容器組件 - 容器組件是處理獲取數據、訂閱 redux 存儲等的組件。它們包含展示組件和其他容器組件,但是里面從來沒有html。
6 高階組件 - 高階組件是將組件作為參數并生成另一個組件的組件。 Redux connect是高階組件的示例。 這是一種用于生成可重用組件的強大技術。
Fiber 是什么?
解決同步阻塞方法,異步和任務分割。
任務分割調度算法,主要是將原先同步更新渲染的任務分割成一個個獨立的小人物,根據優先級。將小任務分散到瀏覽器的空間時間執行,充分利用主進程的時間循環機制。
性能優化方法
- dns預解析
- 瀏覽器緩存,強緩存和協商緩存
- 預加載 將一些不影響首屏但重要的文件延后加載 preload
- 預渲染 prerender
- 懶加載
- 文件優化
- webpack優化 使用到tree shaking。各種loader等等
webpack熱更新原理
核心就是客戶端從服務端拉取更新后的文件,進行一個替換;
實際上 WDS 與瀏覽器之間維護了一個 Websocket,當本地資源發生變化時,WDS 會向瀏覽器推送更新,并帶上構建時的 hash,讓客戶端與上一次資源進行對比。客戶端對比出差異后會向 WDS 發起 Ajax 請求來獲取更改內容(文件列表、hash),這樣客戶端就可以再借助這些信息繼續向 WDS 發起 jsonp 請求獲取該chunk的增量更新。
webpack的構建過程
- 初始化參數:從配置文件和 Shell 語句中讀取與合并參數,得出最終的參數;
- 開始編譯:用上一步得到的參數初始化 Compiler 對象,加載所有配置的插件,執行對象的 run 方法開始執行編譯;
- 確定入口:根據配置中的 entry 找出所有的入口文件;
- 編譯模塊:從入口文件出發,調用所有配置的 Loader 對模塊進行翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有入口依賴的文件都經過了本步驟的處理;
- 完成模塊編譯:在經過第4步使用 Loader 翻譯完所有模塊后,得到了每個模塊被翻譯后的最終內容以及它們之間的依賴關系;
- 輸出資源:根據入口和模塊之間的依賴關系,組裝成一個個包含多個模塊的 Chunk,再把每個 Chunk 轉換成一個單獨的文件加入到輸出列表,這步是可以修改輸出內容的最后機會;
- 輸出完成:在確定好輸出內容后,根據配置確定輸出的路徑和文件名,把文件內容寫入到文件系統。
提升webpack打包速度
- happypack
- dll 采用webpack的 DllPlugin 和 DllReferencePlugin 引入dll,讓一些基本不會改動的代碼先打包成靜態資源,避免反復編譯浪費時間
數組拍平
function flat(arr) {
return arr.reduce((prev, cur) => {
return prev.concat(cur instanceof Array ? flat(cur) : cur)
}, [])
}
如何實現圖片懶加載
當訪問一個頁面的時候,先把img元素或是其他元素的背景圖片路徑替換成一張大小為1*1px圖片的路徑(這樣就只需請求一次),只有當圖片出現在瀏覽器的可視區域內時,才設置圖片真正的路徑,讓圖片顯示出來。這就是圖片懶加載。
通常可以借助IntersectionObserver
API。
了解Service Worker嗎
Service Worker 是運行在瀏覽器背后的獨立線程,一般可以用來實現緩存功能。使用 Service Worker的話,傳輸協議必須為 HTTPS。因為 Service Worker 中涉及到請求攔截,所以必須使用 HTTPS 協議來保障安全。
常見的網站漏洞有哪些?
- 有跨站腳本攻擊(XSS)
- 跨站請求偽造(CSRF)
- 點擊劫持
- SQL注入
- DDOS攻擊
- DNS劫持
xss攻擊
代碼注入攻擊,通常是在目標網站上注入惡意腳本,在用戶瀏覽器上運行。利用這些腳本攻擊者獲取敏感信息
防御措施:
- 驗證碼機制
- 轉義字符
- 內容輸入長度控制
- CSP,禁止加載外域代碼
CSRF攻擊
攻擊者誘導受害者進入第三方網站,在第三方網站中,向被攻擊網站發送跨站請求。利用受害者在被攻擊網站已經獲取的注冊憑證,繞過后臺的用戶驗證,達到冒充用戶對被攻擊的網站執行某項操作的目的。
- 同源檢測
- 在請求地址中添加 token 并驗證
SQL注入
所謂SQL注入,就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令.
輸入URL發生了什么
- 在瀏覽器地址欄輸入URL
- 瀏覽器查看緩存,請求資源在緩存中并且未過期,跳轉到轉碼步驟 如果瀏覽器未緩存,發起新的請求已緩存,檢驗是否過期,未過期直接提供給客戶端,否則進行驗證檢驗是否過期 通常有兩個http頭進行控制,expires和cache-control。
- 瀏覽器解析URL獲取協議,主機,端口,path
- 瀏覽器組裝一個http請求 請求報文
- 瀏覽器獲取主機ip地址:(dns解析過程)過程:瀏覽器緩存 -> 本地緩存-> hosts文件 -> 路由器緩存 -> ISP DNS緩存 -> DNS遞歸查詢
- 打開一個socket與目標地址建立TCP連接,進行三次握手i. 客戶端發送一個TCP的SYN=1,Sep=X的包到服務器端口ii. 服務器返回SYN=1,ACK=X+1,Sep=Y的響應包iii. 客戶端發送ACK=Y+1,Sep=Z
- TCP連接建立發送http請求。
- 服務器接收請求并解析,將請求轉發到服務程序
- 服務器檢查http請求頭是否包含緩存驗證信息,如果驗證緩存新鮮,返回304等對應狀態碼
- 處理程序讀取完整請求并準備http響應,可能需要查詢數據庫等操作
- 服務器將響應報文通過TCP連接發送回瀏覽器
- 瀏覽器接收到http響應,然后根據情況選擇關閉TCP連接或者保留重用。(關閉操作進行第四次揮手)主動方發送Fin=1,Ack=Z,Sep=X的報文被動方發送ACK=X+1,Sep=Z報文被動方發送Fin=1,ACK=X,Sep=Y報文主動方發送ACK=Y,Sep=X報文
- 瀏覽器檢查響應狀態碼。狀態嗎不同 解決的方法不同 1XX 3XX 4XX 5XX區別對待2XX是正常返回
- 如果資源可緩存,進行緩存
- 對響應解碼 例如gzip壓縮
- 根據資源類型決定如何處理
- 假設資源為html文檔
- 解析html文檔 構建dom樹 下載資源,構建css樹,執行js腳本
- 構建dom樹
- 解析過程遇到圖片、樣式表、js文件、啟動下載
- 構建css樹
- 根據dom樹和css樹整合構建渲染樹
- js解析
-
顯示頁面
參考如圖