Brower

301 和 302 的區別是什麼?

  1. 301 永久重定向,(好比baidu.com換成了新域名bd.com,若是我訪問舊地址,就會出現301)瀏覽器會記住(由於永久重定向了,下次在訪問的時候,就會直接訪問新的地址)
  2. 302 臨時重定向(臨時維護,首頁備案,而後跳轉到一個臨時頁面,等備案結束,就取消302)瀏覽器不會記住,由於頗有可能會恢復。

(必考)GET 和 POST 的區別是什麼?

  • 參數。GET 的參數放在 url 的查詢參數裏,POST 的參數(數據)放在請求消息體裏。 安全(扯淡)。GET 沒有 POST 安全(都不安全)
  • GET 的參數(url查詢參數)有長度限制,通常是 1024 個字符。POST 的參數(數據)沒有長度限制(扯淡,4~10Mb 限制)
  • 包。GET 請求只須要發一個包,POST 請求須要發兩個以上包(由於 POST 有消息體)(扯淡,GET 也能夠用消息體)
  • GET 用來讀數據,POST 用來寫數據,POST 不冪等(冪等的意思就是無論發多少次請求,結果都同樣。)

從輸入 URL 到頁面展示中間發生了什麼?

  1. DNS 查詢 DNS 緩存javascript

  2. 創建 TCP 鏈接(三次握手)鏈接複用php

  3. 發送 HTTP 請求(請求的四部分)css

  4. 後臺處理請求html

    • 監聽 80 端口
    • 根據路由
    • 渲染 HTML 模板
    • 生成響應
  5. 發送 HTTP 響應前端

  6. 關閉 TCP 鏈接(四次揮手)java

  7. 解析 HTMLnode

  8. 下載 CSS(緩存webpack

  9. 解析 CSSweb

  10. 下載 JS(緩存面試

  11. 解析 JS

  12. 下載圖片

  13. 解析圖片

  14. 渲染 DOM 樹

  15. 渲染樣式樹

  16. 執行 JS

  17. DNS解析 DNS解析的過程就是瀏覽器查找域名對應的 IP 地址;

  18. TCP鏈接 瀏覽器根據 IP 地址向服務器發起 TCP 鏈接,與瀏覽器創建 TCP 三次握手: (1)主機向服務器發送一個創建鏈接的請求(您好,我想認識您); (2)服務器接到請求後發送贊成鏈接的信號(好的,很高興認識您); (3)主機接到贊成鏈接的信號後,再次向服務器發送了確認信號(我也很高興認識您),自此,主機與服務器二者創建了鏈接。

  19. 發送HTTP請求 瀏覽器根據 URL 內容生成 HTTP 請求報文。HTTP請求報文是由三部分組成: 請求行, 請求報頭和請求正文,其中包含請求文件的位置、請求文件的方式等等。

  20. 服務器處理請求並返回HTTP報文

服務器接到請求後,回想客戶端發送HTTP響應報文。HTTP響應報文也是由三部分組成: 狀態碼, 響應報頭和響應報文。服務器會根據 HTTP 請求中的內容來決定如何獲取相應的 HTML 文件,並將獲得的 HTML 文件發送給瀏覽器。

  1. 瀏覽器解析渲染頁面 瀏覽器是一個邊解析邊渲染的過程。在瀏覽器尚未徹底接收 HTML 文件時便開始渲染、顯示網頁。在執行 HTML 中代碼時,根據須要,瀏覽器會繼續請求圖片、CSS、JavsScript等文件,過程同請求 HTML 。

  2. 關閉TCP鏈接或繼續保持鏈接

(1)主機向服務器發送一個斷開鏈接的請求(不早了,我該走了);

(2)服務器接到請求後發送確認收到請求的信號(知道了);

(3)服務器向主機發送斷開通知(我也該走了);

(4)主機接到斷開通知後斷開鏈接並反饋一個確認信號(嗯,好的),服務器收到確認信號後斷開鏈接;

客戶端/服務器模型

  • 客戶端主動發送要求。
  • 被動地等待來自用戶端的要求,處理請求並傳回響應
  • 客戶端等待,而後處理響應。

三次握手

爲何要三次握手? 三次握手: A:我能連你了嗎? B: 能夠連我,你連吧 A:那我連你了 開始發送數據

緣由:由於要保證A/B 均可以收發信息 ,數據才能在AB之間傳輸

TCP 三次握手: (1)主機向服務器發送一個創建鏈接的請求(您好,我想認識您); (2)服務器接到請求後發送贊成鏈接的信號(好的,很高興認識您); (3)主機接到贊成鏈接的信號後,再次向服務器發送了確認信號(我也很高興認識您),自此,主機與服務器二者創建了鏈接。

DOM

  • 什麼是DOM?

    • DOM 是 JavaScript 操做網頁的接口,全稱爲「文檔對象模型」。
    • 它的做用是將網頁轉爲一個 JavaScript 對象,從而能夠用JS進行各類操做(好比增刪內容)。
  • 什麼是DOM樹?

    • 瀏覽器會根據 DOM 模型,將文檔解析成節點。此後HTML中的每一個標籤元素屬性文本都能看作是一個DOM的節點
    • 再由這些節點組成一個樹狀結構(DOM Tree)。
    • 最後提供操做這個樹的各類方法
  • Javascript操做DOM經常使用API總結http://luopq.com/2015/11/30/javascript-dom/

在這裏插入圖片描述
www.cnblogs.com/Ry-yuan/p/6…

在這裏插入圖片描述
5Document.querySelector()

6Document.querySelectorAll()

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

DOM事件模型

一:DOM leave1 好比onclick只是一個屬性,能夠被覆蓋,因此一個元素只能有一個onclick事件 寫在字符串裏至關於運行字符串裏的代碼

在這裏插入圖片描述
在這裏插入圖片描述

二: DOM L2中,事件註冊(事件監聽隊列)

在這裏插入圖片描述
**三:**事件觸發時傳播的方式: 先捕獲到最底層, 再冒泡到最上層

  • 冒泡:addEventListener的第三個參數傳入 false 或者 不傳 參數 兒子,爸爸,爺爺
  • 捕獲:addEventListener的第三個參數傳入 true 爺爺,爸爸,兒子
    在這裏插入圖片描述
    冒泡和捕獲的執行順序不受代碼順序控制。只有同一個元素的事件隊列才受於代碼中的事件綁定順序有關
  • 阻止冒泡 event.stopPropagation()。stopPropagation,中止傳播,不要再告訴父母了,不要再往上執行冒泡事件了
  • 禁止默認效果與阻止冒泡
aTag.addEventListener("click",function(e){
	   e.preventDefault();//禁止默認效果
	   e.stopPropagation();//阻止冒泡
	});
複製代碼

事件觸發通常來講會按照上面的順序進行,可是也有特例,若是給一個目標節點同時註冊冒泡和捕獲事件,事件觸發會按照註冊的順序執行。

// 如下會先打印冒泡而後是捕獲
node.addEventListener('click',(event) =>{
    console.log('冒泡')
},false);
node.addEventListener('click',(event) =>{
    console.log('捕獲 ')
},true)

複製代碼

四:事件委託(事件代理)

事件代理 若是一個節點中的子節點是動態生成的,那麼子節點須要註冊事件的話應該註冊在父節點上

<ul id="ul">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    <script>
        let ul = document.querySelector('##ul')
        ul.addEventListener('click', (event) => {
            console.log(event.target);//li
            console.log(event.currentTarget)//ul
        })
    </script>
複製代碼

事件代理的方式相對於直接給目標註冊事件來講,有節省內存的優勢 event.target和event.currentTarget的區別: event.target是點擊到的最底層的那個元素 event.currentTarget是註冊事件註冊在那個元素上,那個元素就是currentTarget,因此通常是父元素

跨域

1 jsonp

真名的名字應該是:動態標籤跨域請求!即利用動態標籤script進行跨域請求的技術。 面試官:說說jsonp: 爲何要用jsonp? jsonp要解決的是瀏覽器的跨域數據訪問的問題。(兩個不一樣域名的網站)。 因爲同源策略,不一樣域名不能發請求。可是HTML的<script>元素是一個例外,script標籤的請求不受域名限制的,而Ajax是受域名限制的。 如何使用jsonp?

請求方:mataotao.com的前端(瀏覽器),一個網站的前端 響應方:jack.com的後端(服務器),另外一個網站的後端 過程:

  1. 請求方動態建立一個<script>標籤。src指向響應方,同時傳一個查詢參數?callback=xxxfn
  2. 由於<script>獲得響應後會當即執行響應過來的內容。因此響應方根據查詢參數構造形如xxxfn("後臺傳過來的數據")這樣的響應。把要傳的數據寫在callback函數的參數裏。
  3. 請求方瀏覽器接收到響應後, 就會執行xxxfn('後臺傳過來的數據')來獲得後臺傳過來的數據,並處理。

這就是jsonp

jsonp爲何不能用post請求 jsonp是經過動態建立script實現的,而script標籤發送的是get請求。(缺點,get不安全) 優缺點: JSONP 使用簡單且兼容性不錯,可是隻限於 get 請求

返回的狀態碼: 2開頭:成功 3開頭:重定向 4開頭:客戶端錯誤 5開頭:服務器錯誤

Ajax

用 form 能夠發get或post或其餘請求,可是會刷新頁面或新開頁面 用 a 能夠發 get 請求,可是也會刷新頁面或新開頁面 用 img 能夠發 get 請求,可是隻能以圖片的形式展現 用 link 能夠發 get 請求,可是隻能以 CSS、favicon 的形式展現 用 script 能夠發 get 請求,可是隻能以腳本的形式運行。 上面幾個均可以發請求,可是各有缺點。

說說Ajax: Ajax 是JS 能夠用直接發起 任意HTTP 請求的技術。

  1. AJAX 經過原生的XMLHttpRequest對象發出 HTTP 請求
  2. 從服務器獲取響應數據後,能夠局部更新當前網頁,而不用刷新。 使用方法:

具體來講,AJAX 包括如下幾個步驟。

  • 建立 XMLHttpRequest 實例
  • 發出 HTTP 請求
  • 接收服務器傳回的數據
  • 更新網頁數據

面試問題:請使用原生JS發送Ajax請求 通常面試大機率會問這個問題,寫不對必定過不了面試

下面四句代碼必定要記住:

myButton.addEventListener("click",(e)=>{
  //這四句必定要記住
  let request = new XMLHttpRequest();
  request.onreadystatechange = ()=>{
    request.onreadystatechange = ()=>{
      if(request.readyState ===4){//Ajax狀態碼爲4
        console.log("請求和響應都完畢了");
        if ( request.status>=200&&request.status<300){//響應成功(http狀態碼)
          console.log(request.responseText);//打印響應的第四部分,字符串
        }else if(request.status>=400){
          console.log("響應失敗");
        }
      } 
    }
  }
  request.open('GET','/xxx')//配置request.參數分別爲方法和路徑
  request.setRequestHeader('content-type','x-www-form-urlencoded')//設置響應頭必定要寫在
  request.send("a=1&b=2");//發送請求
  //這四句必定要記住
})

複製代碼

XMLHttpRequest.readyState返回一個整數,表示實例對象的當前狀態。該屬性只讀。它可能返回如下值。

0,表示 XMLHttpRequest 實例已經生成,可是實例的open()方法尚未被調用。 1,表示open()方法已經調用,可是實例的send()方法尚未調用,仍然可使用實例的setRequestHeader()方法,設定 HTTP 請求的頭信息。 2,表示實例的send()方法已經調用,而且服務器返回的頭信息和狀態碼已經收到。 3,表示正在接收服務器傳來的數據體(body 部分)。 4,表示服務器返回的數據已經徹底接收,或者本次接收已經失敗。

同源策略

協議+域名+端口徹底相同才叫同源 如下三種行爲受到限制: (1) 沒法讀取非同源網頁的 Cookie、LocalStorage 和 IndexedDB。

(2) 沒法接觸非同源網頁的 DOM

(3) 沒法向非同源地址發送 AJAX 請求(能夠發送,但瀏覽器會拒絕接受響應)。

解決: cookie 瀏覽器經過document.domain屬性來檢查是否同源。 A 網頁的網址是http://w1.example.com/a.html,B 網頁的網址是http://w2.example.com/b.html(一級域名同樣,二級不同)

// 兩個網頁都須要設置
document.domain = 'example.com';
複製代碼

這時候a設置一個cookie,b就能夠讀到這個cookie

AJAX: jsonp CORS(「跨域資源共享」):Access-Control-Allow-Origin

Content-Type: text/html; charset=utf-8

同源策略和CORS(跨域)

什麼是同源策略?formaimglinkscript、均可以跨域發送請求。 可是隻有 協議+域名+端口 如出一轍才容許發 AJAX 請求爲何要有同源策略? 簡單地說就是例如使用form發送請求後,就會刷新頁面,因此原頁面沒有了,就認爲是安全的.可是Ajax能夠吧響應內容讀取了.而且顯示在本頁面上.因此出現安全性問題。

Ajax沒法跨域報的錯誤:

在這裏插入圖片描述

CORS的英文Cross-Origin Resource Sharing,即跨域(源,站)資源共享(跨域) 那麼如何使用CORS突破同源策略解決Ajax的沒法跨域發送請求的問題?

只要服務器端設置響應頭就能夠實現跨域:

response.setHeader('Access-Control-Allow-Origin','http://mataotao.com:8001')
複製代碼

這句話是CORS跨域(突破同源策略)的核心,即容許別的網站(例如http://mataotao.com:8001)跨域向我發Ajax請求,而且容許響應。

爲何不使用jsonp,而是用CORS來跨域? CORS相對於JSONP,CORS能夠發任意請求,而JSONP只能發送get請求

JSON 和 JS 對象互轉

要實現從對象轉換爲 JSON 字符串,使用 JSON.stringify() 方法:

var json = JSON.stringify({a: 'Hello', b: 'World'}); //結果是 '{"a": "Hello", "b": "World"}'
複製代碼

要實現從 JSON 轉換爲對象,使用 JSON.parse() 方法:

var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //結果是 {a: 'Hello', b: 'World'}
複製代碼

Cookie

Cookie 是服務器保存在瀏覽器的一小段文本信息。瀏覽器每次向服務器發出請求,就會自動附上這段信息。 Cookie的做用過程:

  1. 第一次登陸的時候,服務器經過 Set-Cookie 響應頭設置 Cookie,而後以響應的形式發給瀏覽器
  2. 瀏覽器獲得 響應中Cookie 以後,以後每次請求這個域名都要帶上這個 Cookie
  3. 以後服務器讀取當時本身設置的 Cookie 就知道用戶的信息(好比用戶名,是不是同一個瀏覽器等)

COokie的做用:

  1. 分辨兩個請求是否來自同一個瀏覽器
  2. 用來保存一些狀態信息,例如:保存登陸、購物車等須要記錄的信息。

HTTP 迴應:Cookie 的生成(服務器端生成cookies)

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[page content]
複製代碼
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
複製代碼

HTTP 請求:Cookie 的發送(瀏覽器發送Cookie)

瀏覽器向服務器發送 HTTP 請求時,每一個請求都會帶上相應的 Cookie。也就是說,把服務器早前保存在瀏覽器的這段信息,再發回服務器。這時要使用 HTTP 頭信息的Cookie字段。

Cookie: foo=bar
複製代碼

上面代碼會向服務器發送名爲foo的 Cookie,值爲bar。

Cookie字段能夠包含多個 Cookie,使用分號(;)分隔。

Cookie: name=value; name2=value2; name3=value3
複製代碼

下面是一個Http請求的例子。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
複製代碼

讀、寫、刪除、Cookie

  1. document.cookie,前提是該 Cookie 不能有HTTPOnly屬性。

  2. document.cookie寫入 Cookie 的例子以下。

document.cookie = 'fontSize=14; '
  + 'expires=' + someDate.toGMTString() + '; '
  + 'path=/subdirectory; '
  + 'domain=*.example.com';
複製代碼
  1. Cookie 的刪除 刪除一個現存 Cookie 的惟一方法,是設置它的expires屬性爲一個過去的日期

session

什麼是session?

  1. 服務器經過Cookie發送給客戶端一個sessionID
  2. sessionID對應服務器裏的一小塊內存,這裏保存着用戶的信息,例如登陸信息,購物車信息等。
  3. 每次用戶訪問服務器的時候,服務器經過瀏覽器發送來的cookie裏的sessionID去讀取對應的內存裏的信息,以此來知道用戶的隱私信息。

Storage

window.sessionStoragewindow.localStorage接口用於腳本在瀏覽器保存數據。

基本使用

設置

window.sessionStorage.setItem('key', 'value');
window.localStorage.setItem('key', 'value');
複製代碼

獲取

window.sessionStorage.getItem('key')
window.localStorage.getItem('key')
複製代碼

清除

localStorage.removeItem('key');
window.localStorage.clear()
複製代碼

總結

注意只能存字符串類型的。

  1. LocalStorage 跟 HTTP 無關(而cookie是http的一個頭)
  2. 發送HTTP請求時 不會帶上 LocalStorage 的值
  3. 只有相同域名的頁面才能互相讀取 LocalStorage(沒有同源那麼嚴格)
  4. 每一個域名 localStorage 最大存儲量爲 5Mb 左右(每一個瀏覽器不同)
  5. 經常使用場景:記錄有沒有提示過用戶(沒有用的信息,不能記錄密碼)
  6. LocalStorage 永久有效,除非用戶主動清理緩存

區別:SessionStorage 在用戶關閉頁面(會話結束)後就失效。其他的和localstorage同樣

Cookie和Storage對比:

在這裏插入圖片描述

HTTP緩存

HTTP緩存有利於web性能優化。HTTP緩存能夠重複利用以前獲取的資源而不用反覆請求,以達到性能優化的目的。 方法

1 Cache-Control

在響應裏設置響應頭 Cache-Control: max-age=30 意思就是30秒以內,瀏覽器再訪問相同的URL的時候,就不發請求,直接從內存裏拿到已經緩存的main.js。 問題:那麼js和css更新了怎麼辦? 瀏覽器請求時發現是相同的URL才使用緩存,那麼能夠設置查詢參數,例如第二個版本的js能夠寫<script src="./main.js?v=2"></script>,來保證URL的不一樣,從新獲取新的js文件。這樣便可以緩存好久,又能夠隨時更新.(總結:設置查詢參數,保證URL的不一樣)

Expires

  1. Expires 是之前用來控制緩存的http頭,Cache-Control是新版的API。

  2. 如今首選 Cache-Control。

  3. 若是在Cache-Control響應頭設置了 "max-age" 或者 "s-max-age" 指令,那麼 Expires 頭會被忽略。

  4. 響應頭設置方式: Expires: Wed, 21 Oct 2015 07:28:00 GMT

  5. Expires 響應頭包含日期/時間, 即在此時候以後,響應過時。 注意: 由於過時標準的時間用的是本地時間,因此不靠譜,因此要遊俠使用Cache-Control代替Expires

答面試官: 與Cache-Control的區別就是:

  1. Cache-Control設置過時時間長度
  2. Expires 設置過時時間點

MD5是消息摘要算法。用於確保信息傳輸完整一致。能夠判斷兩次信息傳輸是否完整一致

ETag

例如

  1. 咱們請求一個js文件。設置的ETage響應頭爲這個JS文件的MD5值
  2. 那麼,下一次請求這個JS的時候,瀏覽器會把上一次響應的那個ETage的值放到If-None-Match請求頭裏面發送請求。
  3. 若是MD5同樣,說明文件沒改過,那麼返回304

304 Not Modified: HTTP 304 未改變說明無需再次傳輸請求的內容,也就是說能夠使用緩存的內容。

HTTP 304 :沒有響應體

ETag與 Cache-Control的區別

  • 因爲CSS的請求是用緩存(Cache-Control)的,因此直接不發請求
  • 而js用的ETag,有請求也有響應,只不過若是MD5同樣,那麼就不下載響應體。

MVC

MVC是一種代碼組織形式,只是組織代碼的思想.給面試官將MVC

在這裏插入圖片描述
MVC處理的邏輯順序。

MVC就是把代碼分爲三塊

  1. V(view)只負責看得見的東西.
  2. M(model)只負責跟數據相關的操做,不會出現DOM,不會出現任何的html/css操做.例如model裏只會有初始化數據庫,獲取數據方法fetch(),保存數據的方法save()
  3. C(controller)只負責把這些view和model組合起來,找到view,找到model,使用model完成數據修改業務,並修改view的顯示 V:視圖

M,V,C在代碼中能夠用對象或者類來表示

webpack

曾使用 webpack3 用 babel-loader 把 ES6 轉譯爲 ES5 用 sass-loader 把 SCSS 轉譯爲 CSS 做用:

  1. 自從出現模塊化之後,文件變多。每一個 JS 文件都要發送請求響應,會致使加載速度變慢。Webpack 最主要的目的就是爲了解決這個問題,將全部小文件打包成一個或多個大文件。
  2. 可使用各類前端新技術的工具,babel,sass。

安全

XSS

XSS(Cross-site scripting)即跨站點script 舉例

  1. 惡意用戶 A 在網站提交留言爲<script>console.log(document.cookie)</script>,這段代碼被上傳到服務器。
  2. B訪問網站的留言,這段腳本在 B 的瀏覽器直接執行,惡意用戶 H 的腳本就能夠任意操做 B 的 cookie。有了 cookie,惡意用戶 H 就能夠僞造 B 的登陸信息。

產生緣由: 前端的代碼在顯示留言的時候,操做DOM的時候innerHTML方法,或者用了jQuery中的$p.html(content)方法。

解決辦法:

  1. 前端儘可能使用innerText(jQuery就是用text()方法,不要本身)
  2. < >'' ' 這些可疑的符號轉義,如<變成 &lt; (HTML實體)

CSRF攻擊

 (CSRF的全名爲Cross-site request forgery)  僞造跨站請求 過程:

  1. 假設給用戶賺錢的請求連接是:www.game.com/Transfer.ph…
  2. 而後若是客戶端已經驗證並登錄www.game.com網站,此時客戶端瀏覽器保存了遊戲網站的驗證cookie(已登陸,而且瀏覽器保存了須要登陸的cookie)
  3. 客戶端再tab另外一個頁面進行訪問惡意攻擊者的網站,並從惡意攻擊者的網站構造的連接(好比構造一個img標籤,url就是構造的虛假的連接,例如是http://www.game.com/Transfer.php?toUserId=100&vMoney=1000)來訪問遊戲網站(再開一個網頁,這個網頁裏有一個img標籤,url是假的)
  4. 瀏覽器將會攜帶該遊戲網站的cookie進行訪問,1000塊遊戲幣就轉給那個虛假的userid了(由於已經登陸了,瀏覽器裏保存了cookie,因此瀏覽器會帶着這個cookie訪問這個假的img的連接)

對於get請求能夠很輕鬆的攻擊,對於post,攻擊者可誘導用戶進入帶 Form 表單可用POST方式提交參數的頁面。

解決方法:

  1. 服務端在收到路由請求時,生成一個隨機數,在渲染請求頁面時把隨機數埋入頁面(通常埋入 form 表單內,
  2. 服務端設置setCookie,把該隨機數做爲cookie或者session種入用戶瀏覽器
  3. 當用戶發送 GET 或者 POST 請求時帶上_csrf_token參數(對於 Form 表單直接提交便可,由於會自動把當前表單內全部的 input 提交給後臺,包括_csrf_token)
  4. 後臺在接受到請求後解析請求的cookie獲取_csrf_token的值,而後和用戶請求提交的_csrf_token作個比較,若是相等表示請求是合法的。

解決方法: 一Token字符串驗證。 總結:

  1. 服務器請求的時候,生成一個隨機數
  2. 而後埋到要提交的form表單裏,方法是生成一個input標籤頁(
  3. 服務端設置setCookie,把該隨機數做爲cookie保存到客戶端瀏覽器裏
  4. 在發送請求的時候把cookie裏的token隨機數和form表單裏的隨機數進行比較,若是一致,就經過驗證

二讓用戶本身填寫驗證碼

性能優化

  1. HTTP緩存
  2. CSS引用寫在<head></head>,script標籤寫在body閉合標籤前面,先加載內容與樣式。
  3. 圖:懶加載,雪碧圖。
  4. 壓縮代碼:css去掉回車,空格。
  5. CDN:靜態文件放在CDN。
  6. webpack,將幾個小文件組成大文件,減小請求次數。
相關文章
相關標籤/搜索