IP: 互聯網的數據是經過數據包傳遞的,若是要將主機A的數據傳遞到主機B,就須要知道主機B的IP地址,才能正確尋址;額外的,數據包上還會添加上A的IP地址,這樣B才知道怎麼回覆A;可是,B拿到數據包以後,並不知道要交給哪一個程序進行處理,就須要UDP(用戶數據包協議)和TCP協議的幫助;
TCP(傳輸控制協議):上層把數據包傳遞給傳輸層 --> 傳輸層給數據包加上UDP頭交給網絡層 --> 網絡層把IP頭附加在數據包上,交給底層 --> 數據包被傳輸給了B的網絡層,這時候主機B把IP頭拆開,把數據包交給傳輸層 --> 傳輸層把UDP頭拆開,根據端口號交給相應的應用程序進行處理;
TCP的三次握手:主要是爲了確認通訊能力,也就是雙方都有發信和收信的能力,若是不確認的話任何數據傳送都是不穩定的~因此須要三次握手:
客戶端A向服務端B發送報文(B已確認了A的發信能力和B的收信能力) --> 服務端收到報文後,向客戶端發送報文(A已確認了雙方的收發能力) --> A返回ACK並創建鏈接(B確認了A的收信能力和B的發信能力)。TCP鏈接創建後,瀏覽器就能夠利用HTTP/HTTPS協議向服務器發送請求了。
TCP的四次揮手:因爲TCP協議有半關閉的狀態(就是隻能夠接收信息不能夠發生信息),關閉能夠由客戶端或者服務端提出:
二者在established狀態,客戶端A向服務端B提出關閉請求 --> B收到以後,給A發送收到信息的響應,同時通知應用程序關閉相關資源 --> B準備好了以後,給A發送關閉通知消息 --> A回覆B,斷開鏈接。javascript
主要就是在瀏覽器本地把對應的 IP 和域名關聯起來,這樣在進行DNS解析的時候就很快。html
存在內存裏的緩存。不會請求服務器。從優先級上來講,它是瀏覽器最早嘗試去命中的一種緩存。從效率上來講,它是響應速度最快的一種緩存。主要用來緩存圖片、字體、通常腳本等;和渲染進程「生死相依」,tab關掉就沒有了;前端
cache-control: max-age=31536000
比較合適。cache-control比expires優先度更高;這種狀況下網絡請求對應的狀態碼是 304。
協商緩存的實現,從Last-Modified
到Etag
。Last-Modified 是一個時間戳,第一次請求的時候,服務器會返回Last-Modified
,隨後咱們每次請求時,會帶上一個叫 If-Modified-Since
的時間戳字段, 服務器會進行比較;可是存在last-modified
不許確的現象(好比咱們編輯了文件可是內容沒有發生改變,服務器只認修改的時間,所以會去修改last-modified
的值,這樣的話就麼有正確使用協商緩存~),所以有了Etag
,Etag
是由服務器爲每一個資源生成的惟一的標識字符串。vue
Service Worker 是一種獨立於主線程以外的 Javascript 線程。它脫離於瀏覽器窗體,所以沒法直接訪問 DOM。這樣獨立的個性使得 Service Worker 的「我的行爲」沒法干擾頁面的性能,這個「幕後工做者」能夠幫咱們實現離線緩存、消息推送和網絡代理等功能。咱們藉助 Service worker 實現的離線緩存就稱爲 Service Worker Cache。java
Service Worker
GoogleChrome關於service worker的sample.jsgit
service worker是基於web worker發展而來的(web worker主要是由於js是單線程的,用ww能夠開闢一個新的線程,是脫離在主線程以外的,咱們能夠將複雜耗費時間的事情交給web worker來作)。sw是在ww的基礎上增長了離線緩存的能力。github
sw是由事件驅動的,具備生命週期,能夠攔截處理頁面的全部網絡請求(fetch),能夠訪問cache和indexDB,支持推送,而且可讓開發者本身控制管理緩存的內容以及版本,爲離線弱網環境下的 web 的運行提供了可能,讓 web 在體驗上更加貼近 native。換句話說他能夠把你應用裏的全部靜態動態資源根據不一樣策略緩存起來,在你下次打開時再也不須要去服務器請求,這樣一來就減小了網絡耗時,使得web應用能夠秒開,而且在離線環境下也變得可用。作到這一切你只須要增長一個sw文件,不會對原有的代碼產生任何侵入。web
// 頁面註冊service worker if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js'); }); }
service worker的生命週期:
最常綁定的事件:面試
js遵循同源策略,即同協議,同域名,同端口號,不然都算跨域。
下圖幫助理解:
能夠進行跨域的主要有iframe / JSONP / CORS算法
<iframe src="demo.html" height="300" width="500" name="demo" scrolling="auto" sandbox="allow-same-origin"></iframe>
window.top
來防止咱們頁面被嵌套。if(window != window.top){ window.top.location.href = myURL; }
什麼是宏任務和微任務?
異步隊列有宏任務和微任務之分。
宏任務
微任務
從新佈局叫回流,就是改變佈局,每次的迴流都會觸發重繪(repaint), 又要去消耗gpu; 但並非每次repaint都會觸發reflow,好比改個背景色啥的,就不須要從新佈局;
onLoad: 在頁面全部文件加載完成後執行;DomContentLoaded: DOM加載後執行,沒必要等待樣式腳本和圖片下載;
WebSocket 協議實現了瀏覽器與服務器全雙工通訊,能更好的節省服務器資源和帶寬並達到實時通信的目的。它與HTTP同樣經過已創建的TCP鏈接來傳輸數據,可是它和HTTP最大不一樣是:
WebSocket 鏈接必須由瀏覽器發起,請求協議是一個標準的HTTP請求(也就是說,WebSocket的創建是依賴HTTP的)。請求報文格式以下:GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string // 用於標識這個鏈接
Sec-WebSocket-Version: 13 //指定了websocket的協議版本
建立web socket, 指定open、message等事件的回調便可(和web worker和service worker還挺像);
WebSocket 構造函數const ws = new WebSocket('ws://localhost:8080/ws')
webSocket.readyState
CONNECTING: 值爲0
,表示正在鏈接。
OPEN: 值爲1
,表示鏈接成功,能夠通訊了。
CLOSING: 值爲2
,表示鏈接正在關閉。
CLOSED: 值爲3
,表示鏈接已經關閉,或者打開鏈接失敗。
webSocket.onopen : 指定鏈接成功以後的回調函數:
ws.onopen = function() { console.log('hello websocket') }
webSocket.onclose: 指定鏈接關閉以後的回調函數
webSocket.onmessage: 指定收到服務器數據後的回調函數
webSocket.onmessage = function (event) { // 數據多是文本或者二進制數據 if (typeof event.data === 'string') { //... } else if (event.data.instanceof ArrayBuffer) { //... } console.log(event.data) }
webSocket.send: : 實例對象的send()方法用於向服務器發送數據webSocket.send(message)
來自 微信小程序和PWA對比分析
二者和native app最大的區別都是「無需安裝、用完即走」。
咱們全部的App都是界面和數據的交互,因此須要類來進行界面的繪製,因而出現了View,須要類來管理數據因而出現了Model。咱們設計的View應該能顯示任意的內容好比頁面中顯示的文字應該是任意的而不僅是某個特定Model的內容,因此咱們不該該在View的實現中去寫和Model相關的任何代碼,若是這樣作了,那麼View的可擴展性就至關低了。而Model只是負責處理數據的,它根本不知道數據到時候會拿去幹啥,可能拿去做爲算法噼裏啪啦去了,可能拿去顯示給用戶了,它既然沒法接收用戶的交互,它就不該該去管和視圖相關的任何信息,因此Model中不該該寫任何View相關代碼。然而咱們的數據和界面應該同步,也就是必定要有個地方要把Model的數據賦值給View,而Model內部和View的內部都不可能去寫這樣的代碼,因此只能新創造一個類出來了,取名爲Controller。
這張圖把MVC分爲三個獨立的區域,而且中間用了一些線來隔開。頗有意思的設計,由於這些線彷佛出如今了駕校科目一的內容中,你瞧C和V以及C和M之間的白線,一部分是虛線一部分是實線對吧,這就代表了引用關係:C能夠直接引用V和M,而V和M不能直接引用C,至少你不能顯式的在V和M的代碼中去寫和C相關的任何代碼,而V和M之間則是雙黃線,沒錯,它們倆誰也不能引用誰,你既不能在M裏面寫V,也不能在V裏面寫M。哦,上面的描述有點小小的問題,你不是「不能」這樣寫,而是「不該該」這樣寫,沒人能阻止你在寫代碼的時候在一個M裏面去寫V,可是一旦你這樣作了,那麼你就違背了MVC的規範,你就不是在使用MVC了,因此這算是MVC的一個必要條件:使用MVC –> M裏面沒有V的代碼。因此M裏面沒有V的代碼就是使用MVC的必要條件。
MVVM的誕生:
就像咱們以前分析MVC是如何合理分配工做的同樣,咱們須要數據因此有了M,咱們須要界面因此有了V,而咱們須要找一個地方把M賦值給V來顯示,因此有了C,然而咱們忽略了一個很重要的操做:數據解析。在MVC出生的年代,手機APP的數據每每都比較簡單,沒有如今那麼複雜,因此那時的數據解析極可能一步就解決了,因此既然有這樣一個問題要處理,而面向對象的思想就是用類和對象來解決問題,顯然V和M早就被定義死了,它們都不該該處理「解析數據」的問題,理所應當的,「解析數據」這個問題就交給C來完成了。而如今的手機App功能愈來愈複雜,數據結構也愈來愈複雜,因此數據解析也就沒那麼簡單了。若是咱們繼續按照MVC的設計思路,將數據解析的部分放到了Controller裏面,那麼Controller就將變得至關臃腫。還有至關重要的一點:Controller被設計出來並非處理數據解析的。一、管理本身的生命週期;二、處理Controller之間的跳轉;三、實現Controller容器。這裏面根本沒有「數據解析」這一項,因此顯然,數據解析也不該該由Controller來完成。那麼咱們的MVC中,M、V、C都不該該處理數據解析,那麼由誰來呢?這個問題實際上在面向對象的時候至關好回答:既然目前沒有類可以處理這個問題,那麼就建立一個新的類出來解決不就行了?因此咱們聰明的開發者們就專門爲數據解析建立出了一個新的類: ViewModel。這就是MVVM的誕生。