前端知识点整理(三)不定时更新~
目錄
一、移動端跨平臺開發(fā)方案
Hybrid App
React Native
Weex
Flutter?
PWA (Progressive Web App)
小程序
Cordova
html5
組件和模塊的區(qū)別
組件化
模塊化
前端代碼規(guī)范
前端工程化理解
網(wǎng)站性能監(jiān)測與優(yōu)化策略
1.網(wǎng)絡傳輸性能優(yōu)化
頁面加載時,大致可以分為以下幾個步驟:
1.1.瀏覽器緩存
1.2.資源打包壓縮
1.3.圖片資源優(yōu)化
1.4.網(wǎng)絡傳輸性能檢測工具——Page Speed
1.5.使用CDN
2.頁面渲染性能優(yōu)化
2.1.瀏覽器渲染過程(Webkit)
瀏覽器渲染的流程如下:
2.2.DOM渲染層與GPU硬件加速
2.3.重排與重繪
常見引起重排屬性和方法
瀏覽器的渲染隊列:
強制刷新隊列:
重排優(yōu)化建議
1. 分離讀寫操作
2. 樣式集中改變
3. 緩存布局信息
4. 離線改變dom
5. position屬性為absolute或fixed
6. 優(yōu)化動畫
8.壓縮DOM的深度
9.圖片在渲染前指定大小
3.JS阻塞性能
js方面的性能優(yōu)化小建議
4.【拓展】負載均衡
4.2.pm2實現(xiàn)Node.js“多進程”
4.3.nginx搭建反向代理
RESTful架構(gòu)
資源(Resources)
表現(xiàn)層(Representation)
狀態(tài)轉(zhuǎn)化(State Transfer)
綜述
誤區(qū)
一、移動端跨平臺開發(fā)方案
Hybrid App
我們可以把純前端技術(shù)開發(fā)的 Web 網(wǎng)頁稱為 Web App,純原生技術(shù)開發(fā)的應用稱為 Native App,它們各有優(yōu)缺點:純 Native 的迭代太慢,不能動態(tài)更新,且不能跨平臺,而純 Web 則有很多功能無法實現(xiàn),雖然其動畫效果體驗差強人意,但跟原生比還是有些差距。
Hybrid App(混合應用)是指介于這兩者之間的 App,兼具“Native App 良好用戶交互體驗的優(yōu)勢”和“Web App 跨平臺開發(fā)的優(yōu)勢”。
Hybrid 的技術(shù)本質(zhì)是在 WebView 的基礎上,與原生客戶端建立 JS Bridge 橋接,以達到 JS 調(diào)用 Native API 和 Native 執(zhí)行 JS 方法的目的。
React Native
- React Native 官網(wǎng): facebook.github.io/react-nativ…
- React Native 中文網(wǎng): reactnative.cn/
- GitHub 上有個開源庫 awesome-react-native,收集了大量 React Native 的開發(fā)資源,值得關(guān)注: github.com/jondot/awes…
Weex
- Weex 官網(wǎng): weex.incubator.apache.org/
- Weex 中文網(wǎng): weex.incubator.apache.org/cn/
- GitHub 上的 Weex 資源收集項目 awesome-weex: github.com/joggerplus/…
Flutter?
- Flutter 官網(wǎng): flutter.io/
- Flutter 中文網(wǎng): flutterchina.club/
- GitHub 上的 awesome-flutter 匯集了大量的 Flutter 資源: github.com/Solido/awes…
- 此外,知識小集團隊在 GitHub 上開了一個 repo,用于收集 Flutter 國內(nèi)相關(guān)開發(fā)資源,歡迎關(guān)注并和我們一起完善:github.com/awesome-tip…
PWA (Progressive Web App)
- PWA 官網(wǎng): developers.google.com/web/progres…
- GitHub 上的 awesome-pwa: github.com/hemanth/awe…
- 同樣地,我們也在 GitHub 上開了一個 repo,用于收集 PWA 國內(nèi)相關(guān)的開發(fā)資源,歡迎關(guān)注并和我們一起完善: github.com/awesome-tip…
?參考:https://juejin.im/post/5b076e3af265da0dce48fe95
小程序
小程序開發(fā)本質(zhì)上還是前端 HTML + CSS + JS 那一套邏輯,它基于 WebView 和微信自己定義的一套 JS/WXML/WXSS/JSON 來開發(fā)和渲染頁面。微信官方文檔里提到,小程序運行在三端:iOS、Android 和用于調(diào)試的開發(fā)者工具,三端的腳本執(zhí)行環(huán)境以及用于渲染非原生組件的環(huán)境是各不相同的:
- 在 iOS 上,小程序的 JavaScript 代碼是運行在 JavaScriptCore 中,是由 WKWebView 來渲染的,環(huán)境有 iOS 8+;
- 在 Android 上,小程序的 JavaScript 代碼是通過 X5 JSCore 來解析,是由 X5 基于 Mobile Chrome 53/57 內(nèi)核來渲染的;
- 在 開發(fā)工具上, 小程序的 JavaScript 代碼是運行在 nwjs 中,是由 Chrome Webview 來渲染的。
更多細節(jié)請查閱微信小程序官網(wǎng):
- mp.weixin.qq.com/cgi-bin/wx
支付寶后來也上線了自己的小程序平臺:
- open.alipay.com/channel/min…
因為微信或支付寶都可以在 Android 和 iOS 上運行,所以某種意義上,我們也可以把小程序理解為是一種跨平臺開發(fā)。
Cordova
- Cardova 官網(wǎng):?cordova.apache.org/
- Cardova 中文網(wǎng):?cordova.axuer.com/?
html5
HTML5?是定義?HTML?標準的最新的版本。?該術(shù)語通過兩個不同的概念來表現(xiàn):
- 它是一個新版本的HTML語言,具有新的元素,屬性和行為,
- 它有更大的技術(shù)集,允許構(gòu)建更多樣化和更強大的網(wǎng)站和應用程序。這個集合有時稱為HTML5和它的朋友們,不過大多數(shù)時候僅縮寫為一個詞?HTML5。
根據(jù)其功能分為幾個組:
- 語義:能夠讓你更恰當?shù)孛枋瞿愕膬?nèi)容是什么。
- 連通性:能夠讓你和服務器之間通過創(chuàng)新的新技術(shù)方法進行通信。
- 離線 & 存儲:能夠讓網(wǎng)頁在客戶端本地存儲數(shù)據(jù)以及更高效地離線運行。
- 多媒體:使 video 和 audio 成為了在所有 Web 中的一等公民。
- 2D/3D 繪圖 & 效果:提供了一個更加分化范圍的呈現(xiàn)選擇。
- 性能 & 集成:提供了非常顯著的性能優(yōu)化和更有效的計算機硬件使用。
- 設備訪問 Device Access:能夠處理各種輸入和輸出設備。
- 樣式設計: 讓作者們來創(chuàng)作更加復雜的主題吧!
參考:https://developer.mozilla.org/zh-CN/docs/Web/Guide/HTML/HTML5
組件和模塊的區(qū)別
組件化
含義:就是"基礎庫"或者“基礎組件",意思是把代碼重復的部分提煉出一個個組件供給功能使用。
使用:Dialog,各種自定義的UI控件、能在項目或者不同項目重復應用的代碼等等。
目的:復用,解耦。
依賴:組件之間低依賴,比較獨立。
架構(gòu)定位:縱向分層(位于架構(gòu)底層,被其他層所依賴)。
總結(jié):組件相當于庫,把一些能在項目里或者不同類型項目中可復用的代碼進行工具性的封裝。
模塊化
含義:就是"業(yè)務框架"或者“業(yè)務模塊",也可以理解為“框架”,意思是把功能進行劃分,將同一類型的代碼整合在一起,所以模塊的功能相對復雜,但都同屬于一個業(yè)務。
使用:按照項目功能需求劃分成不同類型的業(yè)務框架(例如:注冊、登錄、外賣、直播.....)
目的:隔離/封裝 (高內(nèi)聚)。
依賴:模塊之間有依賴的關(guān)系,可通過路由器進行模塊之間的耦合問題。
架構(gòu)定位:橫向分塊(位于架構(gòu)業(yè)務框架層)。
總結(jié):模塊相應于業(yè)務邏輯模塊,把同一類型項目里的功能邏輯進行進行需求性的封裝。
參考:https://www.jianshu.com/p/cac0beae8876
前端代碼規(guī)范
參考:https://guide.aotu.io/docs/html/code.html
CommonJs與ES6的模塊加載機制
目前階段,通過 Babel 轉(zhuǎn)碼,CommonJS 模塊的require命令和 ES6 模塊的import命令,可以寫在同一個模塊里面,但是最好不要這樣做。因為import在靜態(tài)解析階段執(zhí)行,所以它是一個模塊之中最早執(zhí)行的。
ES6模塊
ES6 的模塊自動采用嚴格模式,不管你有沒有在模塊頭部加上"use strict";。
嚴格模式主要有以下限制。
- 變量必須聲明后再使用
- 函數(shù)的參數(shù)不能有同名屬性,否則報錯
- 不能使用with語句
- 不能對只讀屬性賦值,否則報錯
- 不能使用前綴 0 表示八進制數(shù),否則報錯
- 不能刪除不可刪除的屬性,否則報錯
- 不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
- eval不會在它的外層作用域引入變量
- eval和arguments不能被重新賦值
- arguments不會自動反映函數(shù)參數(shù)的變化
- 不能使用arguments.callee
- 不能使用arguments.caller
- 禁止this指向全局對象
- 不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧
- 增加了保留字(比如protected、static和interface)?
瀏覽器加載 ES6 模塊,也使用<script>標簽,但是要加入type="module"屬性。
<script type="module" src="./foo.js"></script>上面代碼在網(wǎng)頁中插入一個模塊foo.js,由于type屬性設為module,所以瀏覽器知道這是一個 ES6 模塊。
瀏覽器對于帶有type="module"的<script>,都是異步加載,不會造成堵塞瀏覽器,即等到整個頁面渲染完,再執(zhí)行模塊腳本,等同于打開了<script>標簽的defer屬性。
<script type="module" src="./foo.js"></script> <!-- 等同于 --> <script type="module" src="./foo.js" defer></script>如果網(wǎng)頁有多個<script type="module">,它們會按照在頁面出現(xiàn)的順序依次執(zhí)行。
對于外部的模塊腳本(上例是foo.js),有幾點需要注意。
- 代碼是在模塊作用域之中運行,而不是在全局作用域運行。模塊內(nèi)部的頂層變量,外部不可見。
- 模塊腳本自動采用嚴格模式,不管有沒有聲明use strict。
- 模塊之中,可以使用import命令加載其他模塊(.js后綴不可省略,需要提供絕對 URL 或相對 URL),也可以使用export命令輸出對外接口。
- 模塊之中,頂層的this關(guān)鍵字返回undefined,而不是指向window。也就是說,在模塊頂層使用this關(guān)鍵字,是無意義的。
- 同一個模塊如果加載多次,將只執(zhí)行一次。
?ES6 模塊與 CommonJS 模塊的差異
討論 Node.js 加載 ES6 模塊之前,必須了解 ES6 模塊與 CommonJS 模塊完全不同。
它們有兩個重大差異。
- CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。
- CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。
第二個差異是因為 CommonJS 加載的是一個對象(即module.exports屬性),該對象只有在腳本運行完才會生成。而 ES6 模塊不是對象,它的對外接口只是一種靜態(tài)定義,在代碼靜態(tài)解析階段就會生成。
下面重點解釋第一個差異。
CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個值,模塊內(nèi)部的變化就影響不到這個值。
ES6 模塊的運行機制與 CommonJS 不一樣。JS 引擎對腳本靜態(tài)分析的時候,遇到模塊加載命令import,就會生成一個只讀引用。等到腳本真正執(zhí)行時,再根據(jù)這個只讀引用,到被加載的那個模塊里面去取值。換句話說,ES6 的import有點像 Unix 系統(tǒng)的“符號連接”,原始值變了,import加載的值也會跟著變。因此,ES6 模塊是動態(tài)引用,并且不會緩存值,模塊里面的變量綁定其所在的模塊。
ES6 模塊不會緩存運行結(jié)果,而是動態(tài)地去被加載的模塊取值,并且變量總是綁定其所在的模塊。
不同的腳本加載相同模塊,得到的都是同一個實例。
Node.js 加載
Node.js 對 ES6 模塊的處理比較麻煩,因為它有自己的 CommonJS 模塊格式,與 ES6 模塊格式是不兼容的。目前的解決方案是,將兩者分開,ES6 模塊和 CommonJS 采用各自的加載方案。從 v13.2 版本開始,Node.js 已經(jīng)默認打開了 ES6 模塊支持。
Node.js 要求 ES6 模塊采用.mjs后綴文件名。也就是說,只要腳本文件里面使用import或者export命令,那么就必須采用.mjs后綴名。Node.js 遇到.mjs文件,就認為它是 ES6 模塊,默認啟用嚴格模式,不必在每個模塊文件頂部指定"use strict"。
如果不希望將后綴名改成.mjs,可以在項目的package.json文件中,指定type字段為module。
{"type": "module" }一旦設置了以后,該目錄里面的 JS 腳本,就被解釋用 ES6 模塊。
# 解釋成 ES6 模塊 $ node my-app.js如果這時還要使用 CommonJS 模塊,那么需要將 CommonJS 腳本的后綴名都改成.cjs。如果沒有type字段,或者type字段為commonjs,則.js腳本會被解釋成 CommonJS 模塊。
參考:https://es6.ruanyifeng.com/#docs/module-loader
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
前端工程化理解
前端工程化本質(zhì)上就是將前端開發(fā)流程,標準化、規(guī)范化、工具化、自動化、簡單化。其主要目的為了提高效率和降低成本,即提高開發(fā)過程中的開發(fā)效率,減少不必要的重復工作時間。提高編碼、測試、維護階段的生產(chǎn)效率。讓前端開發(fā)自成體系
參考:https://juejin.im/post/5e999cecf265da47cd357a24
網(wǎng)站性能監(jiān)測與優(yōu)化策略
從性能優(yōu)化的三大方面工作逐步展開介紹,其中包括網(wǎng)絡傳輸性能、頁面渲染性能以及JS阻塞性能,系統(tǒng)性地帶著讀者們體驗性能優(yōu)化的實踐流程。
1.網(wǎng)絡傳輸性能優(yōu)化
Resource Timing API提供了有關(guān)每個資產(chǎn)接收時間的詳細信息。請求生命周期的主要階段是:
- 重新導向
- 立即開始startTime。
- 如果發(fā)生重定向,則也將redirectStart開始。
- 如果在此階段結(jié)束時發(fā)生重定向,redirectEnd則將采取重定向。
- 應用緩存(觀察網(wǎng)頁加載順序,第一個都是document文件先加載,之后查看document里需要哪些文件,如果緩存有則不再重復請求,所以是否可將“應用緩存”放在“處理響應文件”那一步)
- 如果應用緩存滿足了請求,fetchStart則將花費一些時間。
- 域名解析
- domainLookupStart?時間是在DNS請求開始時開始的。
- domainLookupEnd?時間是在DNS請求結(jié)束時開始的。
- TCP協(xié)議
- connectStart?最初連接服務器時采用。
- 如果使用TLS或SSL,secureConnectionStart則將在握手開始以確保連接安全時開始。
- connectEnd?與服務器的連接完成后進行。
- 請求
- requestStart?對資源的請求已發(fā)送到服務器后,將采用此命令。
- 響應
- responseStart?是服務器最初響應請求的時間。
- responseEnd?是請求結(jié)束并檢索數(shù)據(jù)的時間。
- 處理響應文件
- domLoading?開始解析渲染 DOM 樹的時間,此時 Document.readyState 變?yōu)?loading,并將拋出 readystatechange 相關(guān)事件
- domInteractive?表示瀏覽器已經(jīng)解析好dom樹了,當前網(wǎng)頁DOM結(jié)構(gòu)結(jié)束解析、開始加載內(nèi)嵌資源
- domContentLoadedEventStart?開始觸發(fā)DomContentLoaded事件,DOM 解析完成后,網(wǎng)頁內(nèi)資源加載開始的時間
- domContentLoadedEnd?DomContentLoaded事件結(jié)束,DOM 解析完成后,網(wǎng)頁內(nèi)資源加載完成的時間(如 JS 腳本加載執(zhí)行完畢)
- domComplete?DOM 樹解析渲染完成,且資源也準備就緒的時間(包括圖像、腳本文件、CSS 文件等),Document.readyState 變?yōu)?complete,并將拋出 readystatechange 相關(guān)事件
- loadEventStart?load 事件發(fā)送給文檔,也即 load 回調(diào)函數(shù)開始執(zhí)行的時間
- loadEventEnd?load 事件的回調(diào)函數(shù)執(zhí)行完畢的時間
參考:http://www.alloyteam.com/2015/09/explore-performance/
這是navigation timing監(jiān)測指標圖,從圖中我們可以看出,瀏覽器在得到用戶請求之后,經(jīng)歷了下面這些階段:重定向→拉取緩存→DNS查詢→建立TCP鏈接→發(fā)起請求→接收響應→處理HTML元素→元素加載完成。
例如發(fā)送一個請求,會經(jīng)過如下:
排隊
排隊的請求表明:
- 該請求被渲染引擎推遲了,因為它被認為比關(guān)鍵資源(例如腳本/樣式)的優(yōu)先級低。這通常發(fā)生在圖像上。
- 該請求被暫停以等待將要釋放的不可用的TCP套接字。
- 由于瀏覽器在HTTP 1上每個源僅允許六個TCP連接,因此該請求被暫停。
- 花在制作磁盤緩存條目上的時間(通常非常快。)
?堵轉(zhuǎn)/堵轉(zhuǎn)
請求等待發(fā)送之前花費的時間。它可能正在等待隊列中描述的任何原因。此外,此時間包括在代理協(xié)商中花費的任何時間。
?代理協(xié)商
與代理服務器連接進行協(xié)商所花費的時間。
DNS查詢
執(zhí)行DNS查找所花費的時間。頁面上的每個新域都需要完整的往返來進行DNS查找。
?初始連接/連接
建立連接所花費的時間,包括TCP握手/重試和協(xié)商SSL。
?SSL協(xié)議
完成SSL握手所花費的時間。
?請求發(fā)送/發(fā)送
發(fā)出網(wǎng)絡請求所花費的時間。通常為一毫秒的時間。
等待中(TTFB)
等待初始響應所花費的時間,也稱為第一個字節(jié)的時間。除了等待服務器傳遞響應所花費的時間之外,該時間還捕獲了到服務器的往返延遲。
?內(nèi)容下載/下載
接收響應數(shù)據(jù)所花費的時間。
參考:https://developers.google.cn/web/tools/chrome-devtools/network/understanding-resource-timing
頁面加載時,大致可以分為以下幾個步驟:
1.1.瀏覽器緩存
我們都知道,瀏覽器在向服務器發(fā)起請求前,會先查詢本地是否有相同的文件,如果有,就會直接拉取本地緩存,這和我們在后臺部屬的Redis、Memcache類似,都是起到了中間緩沖的作用,我們先看看瀏覽器處理緩存的策略:
瀏覽器默認的緩存是放在內(nèi)存內(nèi)的,但我們知道,內(nèi)存里的緩存會因為進程的結(jié)束或者說瀏覽器的關(guān)閉而被清除,而存在硬盤里的緩存才能夠被長期保留下去。很多時候,我們在network面板中各請求的size項里,會看到兩種不同的狀態(tài):from memory cache 和 from disk cache,前者指緩存來自內(nèi)存,后者指緩存來自硬盤。而控制緩存存放位置的,不是別人,就是我們在服務器上設置的Etag字段。在瀏覽器接收到服務器響應后,會檢測響應頭部(Header),如果有Etag字段,那么瀏覽器就會將本次緩存寫入硬盤中。
之所以拉取緩存會出現(xiàn)200、304兩種不同的狀態(tài)碼,取決于瀏覽器是否有向服務器發(fā)起驗證請求。 只有向服務器發(fā)起驗證請求并確認緩存未被更新,才會返回304狀態(tài)碼。
【!!!特別注意!!!】在我們配置緩存時一定要切記,瀏覽器在處理用戶請求時,如果命中強緩存,瀏覽器會直接拉取本地緩存,不會與服務器發(fā)生任何通信,也就是說,如果我們在服務器端更新了文件,并不會被瀏覽器得知,就無法替換失效的緩存。所以我們在構(gòu)建階段,需要為我們的靜態(tài)資源添加md5 hash后綴,避免資源更新而引起的前后端文件無法同步的問題。
1.2.資源打包壓縮
我們之前所作的瀏覽器緩存工作,只有在用戶第二次訪問我們的頁面才能起到效果,如果要在用戶首次打開頁面就實現(xiàn)優(yōu)良的性能,必須對資源進行優(yōu)化。我們常將網(wǎng)絡性能優(yōu)化措施歸結(jié)為三大方面:減少請求數(shù)、減小請求資源體積、提升網(wǎng)絡傳輸速率。現(xiàn)在,讓我們逐個擊破:
結(jié)合前端工程化思想,我們在對上線文件進行自動化打包編譯時,通常都需要打包工具的協(xié)助,這里我推薦webpack,我通常都使用Gulp和Grunt來編譯node
在對webpack進行上線配置時,我們要特別注意以下幾點:
①JS壓縮:(這點應該算是耳熟能詳了,就不多介紹了)
②HTML壓縮
③提取公共資源
④提取css并壓縮
⑤使用webpack3的新特性:ModuleConcatenationPlugin
⑥在服務器上開啟Gzip傳輸壓縮,它能將我們的文本類文件體積壓縮至原先的四分之一,效果立竿見影
如果你在網(wǎng)站請求的響應頭里看到這樣的字段,那么就說明咱們的Gzip壓縮配置成功啦:
?
【!!!特別注意!!!】不要對圖片文件進行Gzip壓縮!不要對圖片文件進行Gzip壓縮!不要對圖片文件進行Gzip壓縮!我只會告訴你效果適得其反,至于具體原因,還得考慮服務器壓縮過程中的CPU占用還有壓縮率等指標,對圖片進行壓縮不但會占用后臺大量資源,壓縮效果其實并不可觀,可以說是“弊大于利”,所以請在gzip_types 把圖片的相關(guān)項去掉。針對圖片的相關(guān)處理,我們接下來會更加具體地介紹。
1.3.圖片資源優(yōu)化
剛剛我們介紹了資源打包壓縮,只是停留在了代碼層面,而在我們實際開發(fā)中,真正占用了大量網(wǎng)絡傳輸資源的,并不是這些文件,而是圖片,如果你對圖片進行了優(yōu)化工作,你能立刻看見明顯的效果。
1.3.1.不要在HTML里縮放圖像
需要用多大的圖片時,就在服務器上準備好多大的圖片,盡量固定圖片尺寸。
1.3.2.使用雪碧圖(CSS Sprite)
這里給大家推薦一個自動化生成雪碧圖的工具:www.toptal.com/developers/…?
1.3.3.使用字體圖標(iconfont)
阿里矢量圖標庫(網(wǎng)址:www.iconfont.cn/?),圖片能做的很多事情,矢量圖都能作,而且它只是往HTML里插入字符和CSS樣式而已,和圖片請求比起來,在網(wǎng)絡傳輸資源的占用上它們完全不在一個數(shù)量級,如果你的項目里有大量的小圖標,就用矢量圖吧。
1.3.4.使用WebP
WebP格式,是谷歌公司開發(fā)的一種旨在加快圖片加載速度的圖片格式。圖片壓縮體積大約只有JPEG的2/3,并能節(jié)省大量的服務器帶寬資源和數(shù)據(jù)空間。Facebook、Ebay等知名網(wǎng)站已經(jīng)開始測試并使用WebP格式。
我們可以使用官網(wǎng)提供的Linux命令行工具對項目中的圖片進行WebP編碼,也可以使用我們的線上服務,這里我推薦叉拍云(網(wǎng)址:www.upyun.com/webp )。但是在實際的上線工作中,我們還是得編寫Shell腳本使用命令行工具進行批量編碼,不過測試階段我們用線上服務就足夠了,方便快捷。
1.4.網(wǎng)絡傳輸性能檢測工具——Page Speed
谷歌監(jiān)測網(wǎng)絡傳輸性能的插件——PageSpeed Insights for Chrome
Page Speed最人性化的地方,便是它會對測試網(wǎng)站的性能瓶頸提出完整的建議,我們可以根據(jù)它的提示進行優(yōu)化工作。這里我的網(wǎng)站已經(jīng)優(yōu)化到最好指標了(??????)??,Page Speed Score表示你的性能測試得分,100/100表示已經(jīng)沒有需要優(yōu)化的地方。
1.5.使用CDN
再好的性能優(yōu)化實例,也必須在CDN的支撐下才能到達極致。
當然,憑著我們單個人的資金實力(除非你是王思聰)是必定搭建不起來CDN的,不過我們可以使用各大企業(yè)提供的服務,諸如騰訊云等,配置也十分簡單,這里就請大家自行去推敲啦。
其實我們的CDN域名一般是和我們的網(wǎng)站主域名不同的,大家可以看看淘寶、騰訊的官方網(wǎng)站,看看他們存放靜態(tài)資源的CDN域名,都是和主域名不一樣的。為什么要這么做?主要有兩個原因:[內(nèi)容摘選自:bbs.aliyun.com/simple/t116… ]
①便于CDN業(yè)務獨立,能夠獨立配置緩存。為了降低web壓力,CDN系統(tǒng)會遵循Cache-Control和Expires HTTP頭標準對改請求返回的內(nèi)容進行緩存,便于后面的請求不在回源,起到加速功能。而傳統(tǒng)CDN(Web與CDN共用域名)的方式,需要對不同類型的文件設置相應的Cache規(guī)則或者遵循后端的HTTP頭,但這樣難以發(fā)揮CDN的最大優(yōu)勢,因為動態(tài)請求回源的概率非常之大,如果訪客與源站的線路并不慢,通過CDN的請求未必快于直接請求源站的。 大型網(wǎng)站為了提升web性能到極致,通常緩存頭設置比較大,像谷歌JS設置一年緩存,百度首頁logo設置十年緩存,如果將靜態(tài)元素抽取出來,就可以很方便的對所有靜態(tài)元素部署規(guī)則,而不用考慮動態(tài)請求。減少規(guī)則的條數(shù)可以提升CDN的效率。
②拋開無用cookie,減小帶寬占用。我們都知道HTTP協(xié)議每次發(fā)送請求都會自動帶上該域名及父級域名下的cookie,但對于CSS,JS還有圖片資源,這些cookie是沒用的,反而會浪費訪客帶寬和服務器入帶寬。而我們的主站,為了保持會話或者做其他緩存,都會存放著大量的cookie,所以如果將CDN與主站域名分離,就能解決這一問題。
不過這樣一來,新的問題就出現(xiàn)了:CDN域名與主站域名不同,DNS解析CDN域名還需要花費額外的時間,增加網(wǎng)絡延遲。不過這難不住我們偉大的程序員前輩,DNS Prefetch閃亮登場。
如果大家翻看大型網(wǎng)站的HTML源代碼,都會在頭部發(fā)現(xiàn)這樣的link鏈接:(這里以淘寶首頁為例)
這就是DNS Prefetch。DNS Prefetch是一種DNS預解析技術(shù),當我們?yōu)g覽網(wǎng)頁時,瀏覽器會在加載網(wǎng)頁時對網(wǎng)頁中的域名進行預解析并緩存,這樣在瀏覽器加載網(wǎng)頁中的鏈接時,就無需進行DNS解析,減少用戶的等待時間,提高用戶體驗。DNS Prefetch現(xiàn)已被主流瀏覽器支持,大多數(shù)瀏覽器針對DNS解析都進行了優(yōu)化,典型的一次DNS解析會耗費20~120ms,減少DNS解析時間和次數(shù)是個很好的優(yōu)化措施。
大公司的靜態(tài)資源優(yōu)化方案,基本上要實現(xiàn)這么幾個東西:
參考:https://www.zhihu.com/question/20790576/answer/32602154
2.頁面渲染性能優(yōu)化
2.1.瀏覽器渲染過程(Webkit)
?
瀏覽器渲染的流程如下:
第四步和第五步是最耗時的部分,這兩步合起來,就是我們通常所說的渲染。
網(wǎng)頁生成的時候,至少會渲染一次。
在用戶訪問的過程中,還會不斷重新渲染
重新渲染需要重復之前的第四步(重新生成布局)+第五步(重新繪制)或者只有第五個步(重新繪制)。
注意:
-
css加載不會阻塞DOM樹的解析
-
css加載會阻塞DOM樹的渲染,由于Render Tree是依賴于DOM Tree和CSSOM Tree的,所以他必須等待到CSSOM Tree構(gòu)建完成,也就是CSS資源加載完成(或者CSS資源加載失敗)后,才能開始渲染。因此,CSS加載是會阻塞Dom的渲染的。
-
css加載會阻塞后面js語句的執(zhí)行
?link和@import的區(qū)別
結(jié)論
就結(jié)論而言,強烈建議使用link標簽,慎用@import方式。
這樣可以避免考慮@import的語法規(guī)則和注意事項,避免產(chǎn)生資源文件下載順序混亂和http請求過多的煩惱。
區(qū)別
1.從屬關(guān)系區(qū)別
@import是 CSS 提供的語法規(guī)則,只有導入樣式表的作用;link是HTML提供的標簽,不僅可以加載 CSS 文件,還可以定義 RSS、rel 連接屬性等。
2.加載順序區(qū)別
加載頁面時,link標簽引入的 CSS 被同時加載;@import引入的 CSS 將在頁面加載完畢后被加載。
3.兼容性區(qū)別
@import是 CSS2.1 才有的語法,故只可在 IE5+ 才能識別;link標簽作為 HTML 元素,不存在兼容性問題。
4.DOM可控性區(qū)別
可以通過 JS 操作 DOM ,插入link標簽來改變樣式;由于 DOM 方法是基于文檔的,無法使用@import的方式插入樣式。
5.權(quán)重區(qū)別(該項有爭議,下文將詳解)
link引入的樣式權(quán)重大于@import引入的樣式。
css優(yōu)化建議:
1. 內(nèi)聯(lián)首屏關(guān)鍵CSS(Critical CSS)
Github上有一個項目Critical CSS4,可以將屬于首屏的關(guān)鍵樣式提取出來,大家可以看一下該項目,結(jié)合自己的構(gòu)建工具進行使用。當然為了保證正確,大家最好再親自確認下提取出的內(nèi)容是否有缺失。
2. 文件壓縮
相信大家都早已習慣對CSS進行壓縮,現(xiàn)在的構(gòu)建工具,如webpack、gulp/grunt、rollup等也都支持CSS壓縮功能。壓縮后的文件能夠明顯減小,可以大大降低了瀏覽器的加載時間。
3. 去除無用的css
雖然文件壓縮能夠降低文件大小。但CSS文件壓縮通常只會去除無用的空格,這樣就限制了CSS文件的壓縮比例。那是否還有其他手段來精簡CSS呢?答案顯然是肯定的,如果壓縮后的文件仍然超出了預期的大小,我們可以試著找到并刪除代碼中無用的CSS。
一般情況下,會存在這兩種無用的CSS代碼:一種是不同元素或者其他情況下的重復代碼,一種是整個頁面內(nèi)沒有生效的CSS代碼。
當然,如果手動刪除這些無用CSS是很低效的。我們可以借助Uncss7庫來進行。Uncss可以用來移除樣式表中的無用CSS,并且支持多文件和JavaScript注入的CSS。
4. 有選擇地使用選擇器
大多數(shù)朋友應該都知道CSS選擇器的匹配是從右向左進行的,這一策略導致了不同種類的選擇器之間的性能也存在差異。相比于#markdown-content-h3,顯然使用#markdown .content h3時,瀏覽器生成渲染樹(render-tree)所要花費的時間更多。
我們在使用選擇器時,只需要記住以下幾點,其他的可以全憑喜好。
5.?減少使用昂貴的屬性
在瀏覽器繪制屏幕時,所有需要瀏覽器進行操作或計算的屬性相對而言都需要花費更大的代價。當頁面發(fā)生重繪時,它們會降低瀏覽器的渲染性能。所以在編寫CSS時,我們應該盡量減少使用昂貴屬性,如box-shadow/border-radius/filter/透明度/:nth-child等。
6.?不要使用@import
參考:?https://juejin.im/post/5b6133a351882519d346853f
?
?
瀏覽器的解釋器,是包括在渲染引擎內(nèi)的,我們常說的Chrome(現(xiàn)在使用的是Blink引擎)和Safari使用的Webkit引擎,Firefox使用的Gecko引擎,指的就是渲染引擎。而在渲染引擎內(nèi),還包括著我們的HTML解釋器(渲染時用于構(gòu)造DOM樹)、CSS解釋器(渲染時用于合成CSS規(guī)則)還有我們的JS解釋器。不過后來,由于JS的使用越來越重要,工作越來越繁雜,所以JS解釋器也漸漸獨立出來,成為了單獨的JS引擎,就像眾所周知的V8引擎,我們經(jīng)常接觸的Node.js也是用的它。
2.2.DOM渲染層與GPU硬件加速
頁面的真實樣子就是這樣,是由多個DOM元素渲染層(Layers)組成的,實際上一個頁面在構(gòu)建完Render Tree之后,是經(jīng)歷了這樣的流程才最終呈現(xiàn)在我們面前的:
①瀏覽器會先獲取DOM樹并依據(jù)樣式將其分割成多個獨立的渲染層
②CPU將每個層繪制進繪圖中
③將位圖作為紋理上傳至GPU(顯卡)繪制
④GPU將所有的渲染層緩存(如果下次上傳的渲染層沒有發(fā)生變化,GPU就不需要對其進行重繪)并復合多個渲染層最終形成我們的圖像
從上面的步驟我們可以知道,布局是由CPU處理的,而繪制則是由GPU完成的。
把那些一直發(fā)生大量重排重繪的元素提取出來,單獨觸發(fā)一個渲染層,那樣這個元素不就不會“連累”其他元素一塊重繪了對吧。
那么問題來了,什么情況下會觸發(fā)渲染層呢?大家只要記住:
Video元素、WebGL、Canvas、CSS3 3D、CSS濾鏡、z-index大于某個相鄰節(jié)點的元素都會觸發(fā)新的Layer,其實我們最常用的方法,就是給某個元素加上下面的樣式:
transform: translateZ(0); backface-visibility: hidden;這樣就可以觸發(fā)渲染層啦 。
我們把容易觸發(fā)重排重繪的元素單獨觸發(fā)渲染層,讓它與那些“靜態(tài)”元素隔離,讓GPU分擔更多的渲染工作,我們通常把這樣的措施成為硬件加速,或者是GPU加速。大家之前肯定聽過這個說法,現(xiàn)在完全清楚它的原理了吧。
2.3.重排與重繪
①重排(reflow):渲染層內(nèi)的元素布局發(fā)生修改,都會導致頁面重新排列,比如窗口的尺寸發(fā)生變化、刪除或添加DOM元素,修改了影響元素盒子大小的CSS屬性(諸如:width、height、padding)。
②重繪(repaint):繪制,即渲染上色,所有對元素的視覺表現(xiàn)屬性的修改,都會引發(fā)重繪。
不論是重排還是重繪,都會阻塞瀏覽器。要提高網(wǎng)頁性能,就要降低重排和重繪的頻率和成本,近可能少地觸發(fā)重新渲染。正如我們在2.3中提到的,重排是由CPU處理的,而重繪是由GPU處理的,CPU的處理效率遠不及GPU,并且重排一定會引發(fā)重繪,而重繪不一定會引發(fā)重排。所以在性能優(yōu)化工作中,我們更應當著重減少重排的發(fā)生。
常見引起重排屬性和方法
任何會改變元素幾何信息(元素的位置和尺寸大小)的操作,都會觸發(fā)重排,下面列一些栗子:
瀏覽器的渲染隊列:
思考以下代碼將會觸發(fā)幾次渲染?
div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px';根據(jù)我們上文的定義,這段代碼理論上會觸發(fā)4次重排+重繪,因為每一次都改變了元素的幾何屬性,實際上最后只觸發(fā)了一次重排,這都得益于瀏覽器的渲染隊列機制:
當我們修改了元素的幾何屬性,導致瀏覽器觸發(fā)重排或重繪時。它會把該操作放進渲染隊列,等到隊列中的操作到了一定的數(shù)量或者到了一定的時間間隔時,瀏覽器就會批量執(zhí)行這些操作。
強制刷新隊列:
div.style.left = '10px'; console.log(div.offsetLeft); div.style.top = '10px'; console.log(div.offsetTop); div.style.width = '20px'; console.log(div.offsetWidth); div.style.height = '20px'; console.log(div.offsetHeight);這段代碼會觸發(fā)4次重排+重繪,因為在console中你請求的這幾個樣式信息,無論何時瀏覽器都會立即執(zhí)行渲染隊列的任務,即使該值與你操作中修改的值沒關(guān)聯(lián)。
因為隊列中,可能會有影響到這些值的操作,為了給我們最精確的值,瀏覽器會立即重排+重繪。
強制刷新隊列的style樣式請求:
我們在開發(fā)中,應該謹慎的使用這些style請求,注意上下文關(guān)系,避免一行代碼一個重排,這對性能是個巨大的消耗
重排優(yōu)化建議
就像上文提到的我們要盡可能的減少重排次數(shù)、重排范圍,這樣說很泛,下面是一些行之有效的建議,大家可以參考一下。
1. 分離讀寫操作
div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px'; console.log(div.offsetLeft); console.log(div.offsetTop); console.log(div.offsetWidth); console.log(div.offsetHeight);還是上面觸發(fā)4次重排+重繪的代碼,這次只觸發(fā)了一次重排:
在第一個console的時候,瀏覽器把之前上面四個寫操作的渲染隊列都給清空了。剩下的console,因為渲染隊列本來就是空的,所以并沒有觸發(fā)重排,僅僅拿值而已。最最最客觀的解決方案,就是不用JS去操作元素樣式,這也是我最推薦的。
2. 樣式集中改變
div.style.left = '10px'; div.style.top = '10px'; div.style.width = '20px'; div.style.height = '20px';雖然現(xiàn)在大部分瀏覽器有渲染隊列優(yōu)化,不排除有些瀏覽器以及老版本的瀏覽器效率仍然低下:
建議通過改變class或者csstext屬性集中改變樣式
// bad var left = 10; var top = 10; el.style.left = left + "px"; el.style.top = top + "px"; // good el.className += " theclassname"; // good el.style.cssText += "; left: " + left + "px; top: " + top + "px;";3. 緩存布局信息
// bad 強制刷新 觸發(fā)兩次重排 div.style.left = div.offsetLeft + 1 + 'px'; div.style.top = div.offsetTop + 1 + 'px';// good 緩存布局信息 相當于讀寫分離 var curLeft = div.offsetLeft; var curTop = div.offsetTop; div.style.left = curLeft + 1 + 'px'; div.style.top = curTop + 1 + 'px';4. 離線改變dom
-
隱藏要操作的dom
在要操作dom之前,通過display隱藏dom,當操作完成之后,才將元素的display屬性為可見,因為不可見的元素不會觸發(fā)重排和重繪。
dom.display = 'none' // 修改dom樣式 dom.display = 'block' -
通過使用DocumentFragment創(chuàng)建一個dom碎片,在它上面批量操作dom,操作完成之后,再添加到文檔中,這樣只會觸發(fā)一次重排。
-
復制節(jié)點,在副本上工作,然后替換它!
5. position屬性為absolute或fixed
position屬性為absolute或fixed的元素,重排開銷比較小,不用考慮它對其他元素的影響
6. 優(yōu)化動畫
-
可以把動畫效果應用到position屬性為absolute或fixed的元素上,這樣對其他元素影響較小
動畫效果還應犧牲一些平滑,來換取速度,這中間的度自己衡量:
比如實現(xiàn)一個動畫,以1個像素為單位移動這樣最平滑,但是reflow就會過于頻繁,大量消耗CPU資源,如果以3個像素為單位移動則會好很多。
-
啟用GPPU加速
此部分來自優(yōu)化CSS重排重繪與瀏覽器性能
GPU(圖像加速器):
GPU 硬件加速是指應用 GPU 的圖形性能對瀏覽器中的一些圖形操作交給 GPU 來完成,因為 GPU 是專門為處理圖形而設計,所以它在速度和能耗上更有效率。
GPU 加速通常包括以下幾個部分:Canvas2D,布局合成, CSS3轉(zhuǎn)換(transitions),CSS3 3D變換(transforms),WebGL和視頻(video)。
(這項策略需要慎用,得著重考量以犧牲GPU占用率為代價能否換來可期的性能優(yōu)化,畢竟頁面中存在太多的渲染層對于GPU而言也是一種不必要的壓力,通常情況下,我們會對動畫元素采取硬件加速。)
/** 根據(jù)上面的結(jié)論* 將 2d transform 換成 3d* 就可以強制開啟 GPU 加速* 提高動畫性能*/ div {transform: translate3d(10px, 10px, 0); }
7 .?visibility: hidden?減小重繪的壓力
將沒用的元素設為不可見:visibility: hidden,這樣可以減小重繪的壓力,必要的時候再將元素顯示。
8.壓縮DOM的深度
一個渲染層內(nèi)不要有過深的子元素,少用DOM完成頁面樣式,多使用偽元素或者box-shadow取代。
9.圖片在渲染前指定大小
因為img元素是內(nèi)聯(lián)元素,所以在加載圖片后會改變寬高,嚴重的情況會導致整個頁面重排,所以最好在渲染前就指定其大小,或者讓其脫離文檔流。
參考:https://juejin.im/post/5c15f797f265da61141c7f86
3.JS阻塞性能
腳本帶來的問題就是他會阻塞頁面的平行下載,還會提高進程的CPU占用率。更有甚者,現(xiàn)在node.js已經(jīng)在前端開發(fā)中普及,稍有不慎,我們引發(fā)了內(nèi)存泄漏,或者在代碼中誤寫了死循環(huán),會直接造成我們的服務器崩潰。
在編程的過程中,如果我們使用了閉包后未將相關(guān)資源加以釋放,或者引用了外鏈后未將其置空(比如給某DOM元素綁定了事件回調(diào),后來卻remove了該元素),都會造成內(nèi)存泄漏的情況發(fā)生,進而大量占用用戶的CPU,造成卡頓或死機。我們可以使用chrome提供的JavaScript Profile版塊,開啟方式同Layers等版塊
其實瀏覽器強大的內(nèi)存回收機制在大多數(shù)時候避免了這一情況的發(fā)生,即便用戶發(fā)生了死機,他只要結(jié)束相關(guān)進程(或關(guān)閉瀏覽器)就可以解決這一問題,但我們要知道,同樣的情況還會發(fā)生在我們的服務器端,也就是我們的node中,嚴重的情況,會直接造成我們的服務器宕機,網(wǎng)站崩潰。所以更多時候,我們都使用JavaScript Profile版塊來對我們的node服務進行壓力測試,搭配node-inspector 插件,我們能更有效地檢測JS執(zhí)行時各函數(shù)的CPU占用率,針對性地進行優(yōu)化。
(PS:所以沒修煉到一定水平,千萬別在服務端使用閉包,一個是真沒啥用,我們會有更多優(yōu)良的解決辦法,二是真的很容易內(nèi)存泄漏,造成的后果是你無法預期的)
js方面的性能優(yōu)化小建議
①不要使用 with() 語句
和函數(shù)類似 ,with語句會創(chuàng)建自己的作用域,因此會增加其中執(zhí)行的代碼的作用域鏈的長度,由于額外的作用域鏈的查找,在with語句中執(zhí)行的代碼肯定會比外面執(zhí)行的代碼要慢,在能不使用with語句的時候盡量不要使用with語句。
②避免全局查找
在一個函數(shù)中會用到全局對象存儲為局部變量來減少全局查找,因為訪問局部變量的速度要比訪問全局變量的速度更快些
function search() {//當我要使用當前頁面地址和主機域名alert(window.location.href + window.location.host);}//最好的方式是如下這樣 先用一個簡單變量保存起來function search() {var location = window.location;alert(location.href + location.host);}③通過模板元素clone,替代createElement
如果文檔中存在現(xiàn)成的樣板節(jié)點,應該是用cloneNode()方法,因為使用createElement()方法之后,你需要設置多次元素的屬性,使用cloneNode()則可以減少屬性的設置次數(shù)——同樣如果需要創(chuàng)建很多元素,應該先準備一個樣板節(jié)點。
④在循環(huán)時將控制條件和控制變量合并起來
提到性能,在循環(huán)中需要避免的工作一直是個熱門話題,因為循環(huán)會被重復執(zhí)行很多次。所以如果有性能優(yōu)化的需求,先對循環(huán)開刀有可能會獲得最明顯的性能提升。
一種優(yōu)化循環(huán)的方法是在定義循環(huán)的時候,將控制條件和控制變量合并起來,下面是一個沒有將他們合并起來的例子:
for ( var x = 0; x < 10; x++ ) { };當我們要添加什么東西到這個循環(huán)之前,我們發(fā)現(xiàn)有幾個操作在每次迭代都會出現(xiàn)。JavaScript引擎需要:
#1:檢查 x 是否存在 #2:檢查 x 是否小于 0 <span style="color: #888888;">(這里可能有筆誤)</span> #3:使 x 增加 1然而如果你只是迭代元素中的一些元素,那么你可以使用while循環(huán)進行輪轉(zhuǎn)來替代上面這種操作:
var x = 9; do { } while( x-- );⑤注意NodeList
最小化訪問NodeList的次數(shù)可以極大的改進腳本的性能
var images = document.getElementsByTagName('img');for (var i = 0, len = images.length; i < len; i++) {}編寫JavaScript的時候一定要知道何時返回NodeList對象,這樣可以最小化對它們的訪問
要了解了當使用NodeList對象時,合理使用會極大的提升代碼執(zhí)行速度
⑥避免與null進行比較
由于JavaScript是弱類型的,所以它不會做任何的自動類型檢查,所以如果看到與null進行比較的代碼,嘗試使用以下技術(shù)替換:
可以通過?toString()?來獲取每個對象的類型。為了每個對象都能通過?Object.prototype.toString()?來檢測,需要以?Function.prototype.call()?或者?Function.prototype.apply()?的形式來調(diào)用,傳遞要檢查的對象作為第一個參數(shù),稱為?thisArg。?
var toString = Object.prototype.toString;toString.call(new Date); // [object Date] toString.call(new String); // [object String] toString.call(Math); // [object Math] toString.call('hahah'); // [object String]//Since JavaScript 1.8.5 toString.call(undefined); // [object Undefined] toString.call(null); // [object Null]⑦循環(huán)引用
⑧釋放javascript對象
在rich應用中,隨著實例化對象數(shù)量的增加,內(nèi)存消耗會越來越大。所以應當及時釋放對對象的引用,讓GC能夠回收這些內(nèi)存控件。
對象:obj = null
對象屬性:delete obj.myproperty
數(shù)組item:使用數(shù)組的splice方法釋放數(shù)組中不用的item
⑨switch語句相對if較快
通過將case語句按照最可能到最不可能的順序進行組織
?擴展:你不知道的Node.js性能優(yōu)化、Redis【入門】就這一篇!、Redis的優(yōu)勢和特點
前端性能優(yōu)化 24 條建議(2020)
4.【拓展】負載均衡
我們都知道node的核心是事件驅(qū)動,通過Event Loop去異步處理用戶請求,相比于傳統(tǒng)的后端服務,它們都是將用戶的每個請求分配一個進程進行處理,推薦大家去看這樣一篇博文:mp.weixin.qq.com/s?__biz=MzA… 。特別生動地講解了事件驅(qū)動的運行機制,通俗易懂。事件驅(qū)動的最大優(yōu)勢是什么?就是在高并發(fā)IO時,不會造成堵塞,對于直播類網(wǎng)站,這點是至關(guān)重要的,我們有成功的先例——快手,快手強大的IO高并發(fā)究其本質(zhì)一定能追溯到node。
其實現(xiàn)在的企業(yè)級網(wǎng)站,都會搭建一層node作為中間層。大概的網(wǎng)站框架如圖所示:
?
?
4.2.pm2實現(xiàn)Node.js“多進程”
我們都知道node的優(yōu)劣,這里分享一份鏈接,找了挺久寫的還算詳細:www.zhihu.com/question/19… 。其實很多都是老套路,那些說node不行的都是指著node是單進程這一個軟肋開撕,告訴你,我們有解決方案了——pm2。這是它的官網(wǎng):pm2.keymetrics.io/ 。它是一款node.js進程管理器,具體的功能,就是能在你的計算機里的每一個內(nèi)核都啟動一個node.js服務,也就是說如果你的電腦或者服務器是多核處理器(現(xiàn)在也少見單核了吧),它就能啟動多個node.js服務,并且它能夠自動控制負載均衡,會自動將用戶的請求分發(fā)至壓力小的服務進程上處理。聽起來這東西簡直就是神器啊!而且它的功能遠遠不止這些,這里我就不作過多介紹了,大家知道我們在上線的時候需要用到它就行了,安裝的方法也很簡單,直接用npm下到全局就可以了$ npm i pm2 -g具體的使用方法還有相關(guān)特性可以參照官網(wǎng)。
下面是pm2啟動后的效果圖:
?
參考:?https://www.cnblogs.com/chyingp/p/pm2-documentation.html?
4.3.nginx搭建反向代理
在開始搭建工作之前,首先得知道什么是反向代理。可能大家對這個名詞比較陌生,先上一張圖:
?
所謂代理就是我們通常所說的中介,網(wǎng)站的反向代理就是指那臺介于用戶和我們真實服務器之間的服務器(說的我都拗口了),它的作用便是能夠?qū)⒂脩舻恼埱蠓峙涞綁毫^小的服務器上,其機制是輪詢。聽完這句話是不是感覺很耳熟,沒錯,在我介紹pm2的時候也說過同樣的話,反向代理起到的作用同pm2一樣也是實現(xiàn)負載均衡,你現(xiàn)在應該也明白了兩者之間的差異,反向代理是對服務器實現(xiàn)負載均衡,而pm2是對進程實現(xiàn)負載均衡。大家如果想深入了解反向代理的相關(guān)知識,我推薦知乎的一個貼子:www.zhihu.com/question/24… 。
參考:https://juejin.im/post/5b0b7d74518825158e173a0c#heading-18
?
?
?
?
RESTful架構(gòu)
即Representational State Transfer的縮寫。我對這個詞組的翻譯是"表現(xiàn)層狀態(tài)轉(zhuǎn)化"。
要理解RESTful架構(gòu),最好的方法就是去理解Representational State Transfer這個詞組到底是什么意思,它的每一個詞代表了什么涵義。如果你把這個名稱搞懂了,也就不難體會REST是一種什么樣的設計。
資源(Resources)
REST的名稱"表現(xiàn)層狀態(tài)轉(zhuǎn)化"中,省略了主語。"表現(xiàn)層"其實指的是"資源"(Resources)的"表現(xiàn)層"。
所謂"資源",就是網(wǎng)絡上的一個實體,或者說是網(wǎng)絡上的一個具體信息。它可以是一段文本、一張圖片、一首歌曲、一種服務,總之就是一個具體的實在。你可以用一個URI(統(tǒng)一資源定位符)指向它,每種資源對應一個特定的URI。要獲取這個資源,訪問它的URI就可以,因此URI就成了每一個資源的地址或獨一無二的識別符。
所謂"上網(wǎng)",就是與互聯(lián)網(wǎng)上一系列的"資源"互動,調(diào)用它的URI。
表現(xiàn)層(Representation)
"資源"是一種信息實體,它可以有多種外在表現(xiàn)形式。我們把"資源"具體呈現(xiàn)出來的形式,叫做它的"表現(xiàn)層"(Representation)。
比如,文本可以用txt格式表現(xiàn),也可以用HTML格式、XML格式、JSON格式表現(xiàn),甚至可以采用二進制格式;圖片可以用JPG格式表現(xiàn),也可以用PNG格式表現(xiàn)。
URI只代表資源的實體的位置,不代表它的形式。嚴格地說,有些網(wǎng)址最后的".html"后綴名是不必要的,因為這個后綴名表示格式,屬于"表現(xiàn)層"范疇,而URI應該只代表"資源"的位置。它的具體表現(xiàn)形式,應該在HTTP請求的頭信息中用Accept和Content-Type字段指定,這兩個字段才是對"表現(xiàn)層"的描述。
狀態(tài)轉(zhuǎn)化(State Transfer)
訪問一個網(wǎng)站,就代表了客戶端和服務器的一個互動過程。在這個過程中,勢必涉及到數(shù)據(jù)和狀態(tài)的變化。
互聯(lián)網(wǎng)通信協(xié)議HTTP協(xié)議,是一個無狀態(tài)協(xié)議。這意味著,所有的狀態(tài)都保存在服務器端。因此,如果客戶端想要操作服務器,必須通過某種手段,讓服務器端發(fā)生"狀態(tài)轉(zhuǎn)化"(State Transfer)。而這種轉(zhuǎn)化是建立在表現(xiàn)層之上的,所以就是"表現(xiàn)層狀態(tài)轉(zhuǎn)化"。
客戶端用到的手段,只能是HTTP協(xié)議。具體來說,就是HTTP協(xié)議里面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源(也可以用于更新資源),PUT用來更新資源,DELETE用來刪除資源。
綜述
綜合上面的解釋,我們總結(jié)一下什么是RESTful架構(gòu):
(1)每一個URI代表一種資源;
(2)客戶端和服務器之間,傳遞這種資源的所需的外在表現(xiàn)形式類型;
(3)客戶端通過四個HTTP動詞,對服務器端資源進行操作,實現(xiàn)"表現(xiàn)層狀態(tài)轉(zhuǎn)化"。
誤區(qū)
RESTful架構(gòu)有一些典型的設計誤區(qū)。
最常見的一種設計錯誤,就是URI包含動詞。因為"資源"表示一種實體,所以應該是名詞,URI不應該有動詞,動詞應該放在HTTP協(xié)議中。
舉例來說,某個URI是/posts/show/1,其中show是動詞,這個URI就設計錯了,正確的寫法應該是/posts/1,然后用GET方法表示show。
如果某些動作是HTTP動詞表示不了的,你就應該把動作做成一種資源。比如網(wǎng)上匯款,從賬戶1向賬戶2匯款500元,錯誤的URI是:
POST /accounts/1/transfer/500/to/2正確的寫法是把動詞transfer改成名詞transaction,資源不能是動詞,但是可以是一種服務:
POST /transaction HTTP/1.1Host: 127.0.0.1from=1&to=2&amount=500.00另一個設計誤區(qū),就是在URI中加入版本號:
http://www.example.com/app/1.0/foohttp://www.example.com/app/1.1/foohttp://www.example.com/app/2.0/foo因為不同的版本,可以理解成同一種資源的不同表現(xiàn)形式,所以應該采用同一個URI。版本號可以在HTTP請求頭信息的Accept字段中進行區(qū)分(參見Versioning REST Services):
Accept: vnd.example-com.foo+json; version=1.0Accept: vnd.example-com.foo+json; version=1.1Accept: vnd.example-com.foo+json; version=2.0參考:http://www.ruanyifeng.com/blog/2011/09/restful.html
css優(yōu)先級
下面列表中,選擇器類型的優(yōu)先級是遞增的:
通配選擇符(universal selector)(*)關(guān)系選擇符(combinators)(+,?>,?~,?'?',?||)和?否定偽類(negation pseudo-class)(:not())對優(yōu)先級沒有影響。(但是,在?:not()?內(nèi)部聲明的選擇器會影響優(yōu)先級)。
您可以訪問?https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance#Specificity_2? 或者?https://specifishity.com?來了解更多關(guān)于優(yōu)先級的詳細信息。
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的前端知识点整理(三)不定时更新~的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1350B. Orac and Mode
- 下一篇: 前端知识点梳理(一)