摘要:但是還是會阻塞事件,所以會可能在觸發前或后執行,但是一定會在事件前觸發。當監聽到該圖片元素進入可視窗口時,即將自定義屬性中的地址存儲到屬性中,達到懶加載的效果。當代碼執行,線程被凍結。所以的性能讓變慢。
概括 涉及到的分類
網絡層面
構建層面
瀏覽器渲染層面
服務端層面
涉及到的功能點資源的合并與壓縮
圖片編解碼原理和類型選擇
瀏覽器渲染機制
懶加載預加載
瀏覽器存儲
緩存機制
PWA
Vue-SSR
資源合并與壓縮 http請求的過程及潛在的性能優化點理解減少http請求數量和減少請求資源大小兩個優化要點
掌握壓縮與合并的原理
掌握通過在線網站和fis3兩種實現壓縮與合并的方法
瀏覽器的一個請求從發送到返回都經歷了什么動態的加載靜態的資源
dns是否可以通過緩存減少dns查詢時間
網絡請求的過程走最近的網絡環境
相同的靜態資源是否可以緩存
能否減少http請求大小
能否減少http請求數量
服務端渲染
資源的合并與壓縮設計到的性能點減少http請求的數量
減少請求的大小
html壓縮HTML代碼壓縮就是壓縮這些在文本文件中有意義,但是在HTML中不顯示的字符,包括空格,制表符,換行符等,還有一些其他意義的字符,如HTML注釋也可以被壓縮
意義
大型網站意義比較大
如何進行html的壓縮使用在線網站進行壓縮(走構建工具多,公司級在線網站手動壓縮小)
node.js提供了html-minifier工具
后端模板引擎渲染壓縮
css及js壓縮 css的壓縮
無效代碼刪除
注釋、無效字符
css語義合并
css壓縮的方式使用在線網站進行壓縮
使用html-minifier對html中的css進行壓縮
使用clean-css對css進行壓縮
js的壓縮語混亂
無效字符的刪除
空格、注釋、回車等
剔除注釋
代碼語意的縮減和優化
變量名縮短(a,b)等
代碼保護
前端代碼是透明的,客戶端代碼用戶是可以直接看到的,可以輕易被窺探到邏輯和漏洞
js壓縮的方式使用在線網站進行壓縮
使用html-minifier對html中的js進行壓縮
使用uglifyjs2對js進行壓縮
不合并文件可能存在的問題文件與文件有插入之間的上行請求,又增加了N-1個網絡延遲
受丟包問題影響更嚴重
經過代理服務器時可能會被斷開
文件合并缺點
首屏渲染問題
文件合并之后的js變大,如果首頁的渲染依賴這個js的話,整個頁面的渲染要等js請求完才能執行
如果首屏只依賴a.js,只要等a.js完成后就可執行
沒有通過服務器端渲染,現在框架都需要等合并完的文件請求完才能執行,基本都需要等文件合并后的js
緩存失效問題
標記 js`md5`戳
合并之后的js,任何一個改動都會導致大面積的緩存失效
文件合并對應缺點的處理公共庫合并
不同頁面的合并
不同頁面js多帶帶打包
見機行事,隨機應變
文件合并對應方法使用在線網站進行合并
構建階段,使用nodejs進行文件合并
圖片相關優化 一張JPG的解析過程
jpg有損壓縮:雖然損失一些信息,但是肉眼可見影響并不大
png8???----256色 + 支持透明
png24 ----2^24 + 不支持透明
png32??---2^24 +支持透明
文件大小 + 色彩豐富程度
png32是在png24上支持了透明,針對不同的業務場景選擇不同的圖片格式很重要
不同的格式圖片常用的業務場景 不同格式圖片的特點jpg有損壓縮,壓縮率高,不支持透明
png支持透明,瀏覽器兼容性好
webp壓縮程度更好,在ios webview中有兼容性問題
svg矢量圖,代碼內嵌,相對較小,圖片樣式相對簡單的場景(盡量使用,繪制能力有限,圖片簡單用的比較多)
不同格式圖片的使用場景jpg:大部分不需要透明圖片的業務場景
png:大部分需要透明圖片的業務場景
webp:android全部(解碼速度和壓縮率高于jpg和png,但是ios safari還沒支持)
svg:圖片樣式相對簡單的業務場景
圖片壓縮的幾種情況針對真實圖片情況,舍棄一些相對無關緊要的色彩信息
CSS雪碧圖:把你的網站用到的一些圖片整合到一張多帶帶的圖片中
優點:減少HTTP請求的數量(通過backgroundPosition定位所需圖片)
缺點:整合圖片比較大時,加載比較慢(如果這張圖片沒有加載成功,整個頁面會失去圖片信息)facebook官網任然在用,主要pc用的比較多,相對性能比較強
Image-inline:將圖片的內容嵌到html中(減少網站的HTTP請求)
base64信息,減少網站的HTTP請求,如果圖片比較小比較多,時間損耗主要在請求的骨干網絡
使用矢量圖
使用SVG進行矢量圖的繪制
使用icon-font解決icon問題
在android下使用webp
webp的優勢主要體現在它具有更優的圖像數據壓縮算法,能帶來更小的圖片體積,而且擁有肉眼識別無差異的圖像質量;
同時具備了無損和有損的壓縮模式、Alpha透明以及動畫的特性,在JPEG和PNG上的轉化效果都非常優秀、穩定和統一
css和js的裝載與執行 HTML頁面加載渲染的過程 一個網站在瀏覽器端是如何進行渲染的 HTML渲染過程中的一些特點
順序執行,并發加載
詞法分析:從上到下依次解析
通過HTML生成Token對象(當前節點的所有子節點生成后,才會通過next token獲取到當前節點的兄弟節點),最終生成Dom Tree
并發加載:資源請求是并發請求的
并發上限
瀏覽器中可以支持并發請求,不同瀏覽器所支持的并發數量不同(以域名劃分),以Chrome為例,并發上限為6個
優化點: 把CDN資源分布在多個域名下
是否阻塞
css阻塞
css 在head中通過link引入會阻塞頁面的渲染
如果我們把css代碼放在head中去引入的話,那么我們整個頁面的渲染實際上就會等待head中css加載并生成css樹,最終和DOM整合生成RanderTree之后才會進行渲染
為了瀏覽器的渲染,能讓頁面顯示的時候視覺上更好。
避免某些情況,如:假設你放在頁面最底部,用戶打開頁面時,有可能出現,頁面先是顯示一大堆文字或圖片,自上而下,絲毫沒有排版和樣式可言。最后,頁面又恢復所要的效果
- `css`不阻塞`js`的加載,但阻塞`js`的執行 - `css`不阻塞外部腳步的加載(`webkit preloader 預資源加載器`) - `js`阻塞 - 直接通過``)
(這是延遲執行引入的js腳本(即腳本加載是不會導致解析停止,等到document全部解析完畢后,defer-script也加載完畢后,在執行所有的defer-script加載的js代碼,再觸發Domcontentloaded)
- `async`屬性(``) - 這是異步執行引入的`js`腳本文件 - 與`defer`的區別是`async`會在加載完成后就執行,但是不會影響阻塞到解析和渲染。但是還是會阻塞`load`事件,所以`async-script`會可能在`DOMcontentloaded`觸發前或后執行,但是一定會在`load`事件前觸發。懶加載與預加載 懶加載
圖片進入可視區域之后請求圖片資源
對于電商等圖片很多,頁面很長的業務場景適用
減少無效資源的加載
并發加載的資源過多會會阻塞js的加載,影響網站的正常使用
img src被設置之后,webkit解析到之后才去請求這個資源。所以我們希望圖片到達可視區域之后,img src才會被設置進來,沒有到達可視區域前并不現實真正的src,而是類似一個1px的占位符。
場景:電商圖片
預加載圖片等靜態資源在使用之前的提前請求
資源使用到時能從緩存中加載,提升用戶體驗
頁面展示的依賴關系維護
場景:抽獎
懶加載原生js和zepto.lazyload原理
先將img標簽中的src鏈接設為同一張圖片(空白圖片),將其真正的圖片地址存儲再img標簽的自定義屬性中(比如data-src)。當js監聽到該圖片元素進入可視窗口時,即將自定義屬性中的地址存儲到src屬性中,達到懶加載的效果。
注意問題:
關注首屏處理,因為還沒滑動
占位,圖片大小首先需要預設高度,如果沒有設置的話,會全部顯示出來
var viewheight = document.documentElement.clientHeight //可視區域高度 function lazyload(){ var eles = document.querySelectorAll("img[data-original][lazyload]") Array.prototype.forEach.call(eles,function(item,index){ var rect; if(item.dataset.original === "") return; rect = item.getBoundingClientRect(); //返回元素的大小及其相對于視口的 if(rect.bottom >= 0 && rect.top < viewheight){ !function(){ var img = new Image(); img.src = item.dataset.url; img.onload = function(){ item.src = img.src } item.removeAttribute("data-original"); item.removeAttribute("lazyload"); }() } }) } lazyload() document.addEventListener("scroll",lazyload)預加載原生js和preloadJS實現 預加載實現的幾種方式
第一種方式:直接請求下來
第二種方式:image對象
var image = new Image(); image.src = "www.pic26.com/dafdafd/safdas.jpg";
第三種方式:xmlhttprequest
缺點:存在跨域問題
優點:好控制
var xmlhttprequest = new XMLHttpRequest(); xmlhttprequest.onreadystatechange = callback; xmlhttprequest.onprogress = progressCallback; xmlhttprequest.open("GET","http:www.xxx.com",true); xmlhttprequest.send(); function callback(){ if(xmlhttprequest.readyState == 4 && xmlhttprequest.status == 200){ var responseText = xmlhttprequest.responseText; }else{ console.log("Request was unsuccessful:" + xmlhttprequest.status); } } function progressCallback(){ e = e || event; if(e.lengthComputable){ console.log("Received"+e.loaded+"of"+e.total+"bytes") } }
?
PreloadJS模塊
本質:權衡瀏覽器加載能力,讓它盡可能飽和利用起來
重繪與回流 css性能讓javascript變慢要把css相關的外部文件引入放進head中,加載css時,整個頁面的渲染是阻塞的,同樣的執行javascript代碼的時候也是阻塞的,例如javascript死循環。
一個線程 => javascript解析 一個線程 => UI渲染
這兩個線程是互斥的,當UI渲染的時候,javascript的代碼被終止。當javascript代碼執行,UI線程被凍結。所以css的性能讓javascript變慢。
頻繁觸發重繪與回流,會導致UI頻繁渲染,最終導致js變慢
什么是重繪和回流 回流當render tree中的一部分(或全部)因為元素的規模尺寸,布局,隱藏等改變而需要重新構建。這就成為回流(reflow)
當頁面布局和幾何屬性改變時,就需要回流
重繪當render tree中的一些元素需要更新屬性,而這些屬性只是影響元素的外觀,風格,而不影響布局,比如background-color。就稱重繪
關系用到chrome 分析 performance
回流必將引起重繪,但是重繪不一定會引起回流
避免重繪、回流的兩種方法 觸發頁面重布局的一些css屬性
盒子模型相關屬性會觸發重布局
width
height
padding
margin
display
border-width
border
min-height
定位屬性及浮動也會觸發重布局
top
bottom
left
right
position
float
clear
改變節點內部文字結構也會觸發重布局
text-align
overflow-y
font-weight
overflow
font-family
line-height
vertical-align
white-space
font-size
優化點:使用不觸發回流的方案替代觸發回流的方案
只觸發重繪不觸發回流color
border-style、border-radius
visibility
text-decoration
background、background-image、background-position、background-repeat、background-size
outline、outline-color、outline-style、outline-width
box-shadow
新建DOM的過程獲取DOM后分割為多個圖層
對每個圖層的節點計算樣式結果(Recalculate style 樣式重計算)
為每個節點生成圖形和位置(Layout 回流和重布局)
將每個節點繪制填充到圖層位圖中(Paint Setup和Paint 重繪)
圖層作為紋理上傳至gpu
符合多個圖層到頁面上生成最終屏幕圖像(Composite Layers 圖層重組)
瀏覽器繪制DOM的過程是這樣子的:獲取 DOM 并將其分割為多個層(layer),將每個層獨立地繪制進位圖(bitmap)中
將層作為紋理(texture)上傳至 GPU,復合(composite)多個層來生成最終的屏幕圖像
left/top/margin之類的屬性會影響到元素在文檔中的布局,當對布局(layout)進行動畫時,該元素的布局改變可能會影響到其他元素在文檔中的位置,就導致了所有被影響到的元素都要進行重新布局,瀏覽器需要為整個層進行重繪并重新上傳到 GPU,造成了極大的性能開銷。
transform 屬于合成屬性(composite property),對合成屬性進行 transition/animation 動畫將會創建一個合成層(composite layer),這使得被動畫元素在一個獨立的層中進行動畫。
通常情況下,瀏覽器會將一個層的內容先繪制進一個位圖中,然后再作為紋理(texture)上傳到 GPU,只要該層的內容不發生改變,就沒必要進行重繪(repaint),瀏覽器會通過重新復合(recomposite)來形成一個新的幀。
chrome創建圖層的條件將頻繁重繪回流的DOM元素多帶帶作為一個獨立圖層,那么這個DOM元素的重繪和回流的影響只會在這個圖層中
3D或透視變換
CSS 屬性使用加速視頻解碼的 元素
擁有 3D (WebGL) 上下文或加速的
2D 上下文的 元素
復合插件(如 Flash)
進行 opacity/transform 動畫的元素擁有加速
CSS filters 的元素元素有一個包含復合層的后代節點(換句話說,就是一個元素擁有一個子元素,該子元素在自己的層里)
元素有一個 z-index 較低且包含一個復合層的兄弟元素(換句話說就是該元素在復合層上面渲染)
總結:對布局屬性進行動畫,瀏覽器需要為每一幀進行重繪并上傳到 GPU 中對合成屬性進行動畫,瀏覽器會為元素創建一個獨立的復合層,當元素內容沒有發生改變,該層就不會被重繪,瀏覽器會通過重新復合來創建動畫幀
gif圖
總結盡量避免使用觸發回流、重繪的CSS屬性
將重繪、回流的影響范圍限制在多帶帶的圖層(layers)之內
圖層合成過程中消耗很大頁面性能,這時候需要平衡考慮重繪回流的性能消耗
實戰優化點總結
用translate替代top屬性
top會觸發layout,但translate不會
用opacity代替visibility
opacity不會觸發重繪也不會觸發回流,只是改變圖層alpha值,但是必須要將這個圖片獨立出一個圖層
visibility會觸發重繪
不要一條一條的修改DOM的樣式,預先定義好class,然后修改DOM的className
把DOM離線后修改,比如:先把DOM給display:none(有一次reflow),然后你修改100次,然后再把它顯示出來
不要把DOM節點的屬性值放在一個循環里當成循環的變量
offsetHeight、offsetWidth每次都要刷新緩沖區,緩沖機制被破壞
先用變量存儲下來
不要使用table布局,可能很小的一個小改動會造成整個table的重新布局
div只會影響后續樣式的布局
動畫實現的速度的選擇
選擇合適的動畫速度
根據performance量化性能優化
對于動畫新建圖層
啟用gpu硬件加速(并行運算),gpu加速意味著數據需要從cpu走總線到gpu傳輸,需要考慮傳輸損耗.
transform:translateZ(0)
transform:translate3D(0)
瀏覽器存儲 cookies 多種瀏覽器存儲方式并存,如何選擇?因為http請求無狀態,所以需要cookie去維持客戶端狀態
cookie的生成方式:
http-->response header-->set-cookie
js中可以通過document.cookie可以讀寫cookie
cookie的使用用處:
用于瀏覽器端和服務器端的交互(用戶狀態)
客戶端自身數據的存儲
expire:過期時間
cookie的限制:
作為瀏覽器存儲,大小4kb左右
需要設置過期時間 expire
重要屬性:httponly 不支持js讀寫(防止收到模擬請求攻擊)
不太作為存儲方案而是用于維護客戶關系
優化點:cookie中在相關域名下面
cdn的流量損耗
解決方案:cdn的域名和主站域名要分開
localStorage localstorageHTML5設計出來專門用于瀏覽器存儲的
大小為5M左右
僅在客戶端使用,不和服務端進行通信
接口封裝較好
瀏覽器本地緩存方案
sessionstorage會話級別的瀏覽器存儲
大小為5M左右
僅在客戶端使用,不和服務器端進行通信
接口封裝較好
對于表單信息的維護
indexedDBIndexedDB是一種低級API,用于客戶端存儲大量結構化數據。該API使用索引來實現對該數據的高性能搜索。雖然Web
Storage對于存儲叫少量的數據很管用,但對于存儲更大量的結構化數據來說,這種方法不太有用。IndexedDB提供了一個解決方案。
為應用創建離線版本
cdn域名不要帶cookie
localstorage存庫、圖片
cookie種在主站下,二級域名也會攜帶這個域名,造成流量的浪費
Service Worker產生的意義 PWA與Service WorkerPWA(Progressive Web Apps)是一種Web App新模型,并不是具體指某一種前言的技術或者某一個單一的知識點,我們從英文縮寫來看就能看出來,這是一個漸進式的Web App,是通過一系列新的Web特性,配合優秀的UI交互設計,逐步增強Web App的用戶體驗
PWA與Service worker chrome 插件 lighthouse檢測是不是一個漸進式web app
當前手機在弱網環境下能不能加載出來
離線環境下能不能加載出來
特點
可靠:沒有網絡的環境中也能提供基本的頁面訪問,而不會出現“未連接到互聯網”的頁面
快速:針對網頁渲染及網絡數據訪問有較好的優化
融入(Engaging):應用可以被增加到手機桌面,并且和普通應用一樣有全屏、推送等特性
service workerservice worker是一個腳本,瀏覽器獨立于當前頁面,將其在后臺運行,為實現一些不依賴頁面的或者用戶交互的特性打開了一扇大門。在未來這些特性將包括消息推送,背景后臺同步,geofencing(地理圍欄定位),但他將推出的第一個首要的特性,就是攔截和處理網絡請求的能力,包括以編程方式來管理被緩存的響應。案例分析
Service Worker學習與實踐
了解servie worker
chrome://serviceworker-internals/
chrome://inspect/#service-worker/
service worker網絡攔截能力,存儲Cache Storage,實現離線應用
indexedDBcallback && callback()寫法 相當于 if(callback){ callback(); }cookie、session、localStorage、sessionStorage基本操作 indexedDB基本操作
object store:對象存儲 本身就是結構化存儲
function openDB(name, callback) { //建立打開indexdb indexedDB.open var request = window.indexedDB.open(name) request.onerror = function(e) { console.log("on indexedDB error") } request.onsuccess = function(e) { myDB.db = e.target.result callback && callback() } //from no database to first version,first version to second version... request.onupgradeneeded = function() { console.log("created") var store = request.result.createObjectStore("books", { keyPath: "isbn" }) console.log(store) var titleIndex = store.createIndex("by_title", "title", { unique: true }) var authorIndex = store.createIndex("by_author", "author") store.put({ title: "quarry memories", author: "fred", isbn: 123456 }) store.put({ title: "dafd memories", author: "frdfaded", isbn: 12345 }) store.put({ title: "dafd medafdadmories", author: "frdfdsafdafded", isbn: 12345434 }) } } var myDB = { name: "tesDB", version: "2.0.1", db: null } function addData(db, storeName) { } openDB(myDB.name, function() { // myDB.db = e.target.result // window.indexedDB.deleteDatabase(myDB.name) }); //刪除indexedDBindexDB事務
transcation 與 object store建立關聯關系來操作object store
建立之初可以配置
var transcation = db.transcation("books", "readwrite") var store = transcation.objectStore("books") var data =store.get(34314) store.delete(2334) store.add({ title: "dafd medafdadmories", author: "frdfdsafdafded", isbn: 12345434 })Service Worker離線應用
serviceworker需要https協議
如何實現ServiceWorker與主頁面之間的通信lavas
緩存httpheader 可緩存性期望大規模數據能自動化緩存,而不是手動進行緩存,需要瀏覽器端和服務器端協商一種緩存機制
Cache-Control所控制的緩存策略
last-modified 和 etage以及整個服務端瀏覽器端的緩存流程
基于node實踐以上緩存方式
public:表明響應可以被任何對象(包括:發送請求的客戶端,代理服務器,等等)緩存。
private:表明響應只能被單個用戶緩存,不能作為共享緩存(即代理服務器不能緩存它)。
no-cache:強制所有緩存了該響應的緩存用戶,在使用已存儲的緩存數據前,發送帶驗證器的請求到原始服務器
only-if-cached:表明如果緩存存在,只使用緩存,無論原始服務器數據是否有更新
到期
max-age=
s-maxage=
max-stale[=
表明客戶端愿意接收一個已經過期的資源。 可選的設置一個時間(單位秒),表示響應不能超過的過時時間。
min-fresh=
表示客戶端希望在指定的時間內獲取最新的響應。
重新驗證和重新加載重新驗證
must-revalidate:緩存必須在使用之前驗證舊資源的狀態,并且不可使用過期資源。
proxy-revalidate:與must-revalidate作用相同,但它僅適用于共享緩存(例如代理),并被私有緩存忽略。
immutable :表示響應正文不會隨時間而改變。資源(如果未過期)在服務器上不發生改變,因此客戶端不應發送重新驗證請求頭(例如If-None-Match或If-Modified-Since)來檢查更新,即使用戶顯式地刷新頁面。在Firefox中,immutable只能被用在 https:// transactions.
重新加載
no-store:緩存不應存儲有關客戶端請求或服務器響應的任何內容。
no-transform:不得對資源進行轉換或轉變。Content-Encoding, Content-Range, Content-Type等HTTP頭不能由代理修改。例如,非透明代理可以對圖像格式進行轉換,以便節省緩存空間或者減少緩慢鏈路上的流量。 no-transform指令不允許這樣做。
Expires緩存過期時間,用來指定資源到期的時間,是服務器端的時間點
告訴瀏覽器在過期時間前瀏覽器可以直接從瀏覽器緩存中存取數據,而無需再次請求
expires是http1.0的時候的
http1.1時候,我們希望cache的管理統一進行,max-age優先級高于expires,當有max-age在的時候expires可能就會被忽略。
如果沒有設置cache-control時候會使用expires
Last-modified和If-Modified-since基于客戶端和服務器端協商的緩存機制
last-modified --> response header
if-modified-since --> request header
需要與cache-control共同使用
last-modified有什么缺點?
某些服務端不能獲取精確的修改時間
文件修改時間改了,但文件的內容卻沒有變
Etag 和 If-none-match文件內容的hash值
etag -->reponse header
if-none-match -->request header
需要與cache-control共同使用
好處:
比if-modified-since更加準確
優先級比etage更高
流程圖服務端用的node.js因為和前端用的同一種語言,可以利用服務端運算能力來進行相關的運算而減少前端的運算
vue渲染遇到的問題
vue-ssr和原理和引用
vue渲染面臨的問題先加載vue.js => 執行vue.js代碼 => 生成html
以前沒有前端框架時,
用jsp/php在服務端進行數據的填充,發送給客戶端就是已經填充好數據`的html
使用jQuery異步加載數據
使用React和Vue前端框架
代價:需要框架全部加載完,才能把頁面渲染出來,頁面的首屏性能不好
多層次的優化方案構建層的模板編譯。runtime,compile拆開,構建層做模板編譯工作。webpack構建時候,統一,直接編譯成runtime可以執行的代碼
數據無關的prerender的方式
服務端渲染
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102036.html
摘要:前端每周清單年度總結與盤點在過去的八個月中,我幾乎只做了兩件事,工作與整理前端每周清單。本文末尾我會附上清單線索來源與目前共期清單的地址,感謝每一位閱讀鼓勵過的朋友,希望你們能夠繼續支持未來的每周清單。 showImg(https://segmentfault.com/img/remote/1460000010890043); 前端每周清單年度總結與盤點 在過去的八個月中,我幾乎只做了...
摘要:是具有此屬性的域名不需要用戶點擊鏈接就在后臺解析,而域名解析和內容載入是串行的網絡操作,所以這個方式能減少用戶的等待時間,提升用戶體驗。 web前端性能優化主要分為以下幾個板塊: 加載優化 DNS預解析 合并img、css、javascript文件,減少http請求 緩存一切可緩存資源 使用長Cache 使用外聯式引用css、javascript文件 壓縮HTML、css、jav...
摘要:是具有此屬性的域名不需要用戶點擊鏈接就在后臺解析,而域名解析和內容載入是串行的網絡操作,所以這個方式能減少用戶的等待時間,提升用戶體驗。 web前端性能優化主要分為以下幾個板塊: 加載優化 DNS預解析 合并img、css、javascript文件,減少http請求 緩存一切可緩存資源 使用長Cache 使用外聯式引用css、javascript文件 壓縮HTML、css、jav...
閱讀 454·2023-04-25 23:00
閱讀 3486·2021-11-22 13:54
閱讀 1885·2021-10-27 14:14
閱讀 1477·2019-08-30 13:59
閱讀 3502·2019-08-23 16:15
閱讀 1947·2019-08-23 16:06
閱讀 3315·2019-08-23 15:26
閱讀 1246·2019-08-23 13:48