前言:恰逢準備找新工做,整理我的學習以及在大廠面試中彙總的基礎要點難點,覆蓋從計算機基礎到框架上層應用,隨着前端知識覆蓋面愈來愈廣,頗有必要在面試前將基礎打好,攻克層層面試,仍在更新中,進階難點版後期更新新文章,祝各位收割 offer。
github 可收藏查看javascript
進程是資源分配的單位,而線程是系統調度的單位。進程的引入大大地提升了資源的利用率和系統的吞吐量,而引入線程的目的是爲了減小程序併發所付出的系統開銷。css
操做系統中常見的進程調度策略有哪幾種:html
FCFS(先來先服務),優先級,時間片輪轉,多隊列、多級反饋隊列。前端
進程間的通訊如何實現?html5
如今最多見的進程間通訊的方式有:信號,信號量,消息隊列,共享內存,管道。java
信號是使用信號處理器來進行的,信號量是使用P、V操做來實現的。消息隊列是比較高級的一種進程間通訊方法,由於它真的能夠在進程間傳送消息。jquery
單例模式的定義是產生一個類的惟一實例,但js自己是一種「無類」語言。linux
如建立遮罩層:css3
var createMask = function(){ var mask; return function(){ return mask || ( mask = document.body.appendChild( document.createElement('div') ) ) } }()
簡單工廠模式是由一個方法來決定到底要建立哪一個類的實例, 而這些實例常常都擁有相同的接口. 這種模式主要用在所實例化的類型在編譯期並不能肯定, 而是在執行期決定的狀況nginx
觀察者模式( 又叫發佈者-訂閱者模式 )應該是最經常使用的模式之一. 在不少語言裏都獲得大量應用. 包括咱們平時接觸的dom事件. 也是js和dom之間實現的一種觀察者模式.觀察者模式能夠很好的實現2個模塊之間的解耦。
應用: 事件總線EventBus
div.onclick = function click (){ alert ( ''click' ) }
適配器模式的做用很像一個轉接口. 原本iphone的充電器是不能直接插在電腦機箱上的, 而經過一個usb轉接口就能夠了.
在程序裏適配器模式也常常用來適配2個接口, 好比你如今正在用一個自定義的js庫. 裏面有個根據id獲取節點的方法$id(). 有天你以爲jquery裏的$實現得更酷, 但你又不想讓你的工程師去學習新的庫和語法. 那一個適配器就能讓你完成這件事情.
裝飾者模式是一種爲函數或類增添特性的技術,它可讓咱們在不修改原來對象的基礎上,爲其增添新的能力和行爲。它本質上也是一個函數。
場景:
例子:
1.防抖節流函數
2.裝飾者模式除了能夠應用在類上以外,還能夠應用在函數上(其實這就是高階函數)。好比,咱們想測量函數的執行時間,那麼我能夠寫這麼一個裝飾器。
代理模式的定義是把對一個對象的訪問, 交給另外一個代理對象來操做.
橋接模式的做用在於將實現部分和抽象部分分離開來, 以便二者能夠獨立的變化。在實現api的時候, 橋接模式特別有用。好比最開始的singleton的例子.
var singleton = function( fn ){ var result; return function(){ return result || ( result = fn .apply( this, arguments ) ); } } var createMask = singleton( function(){ return document.body.appendChild( document.createElement('div') ); })
另一個常見的例子就是forEach函數的實現, 用來迭代一個數組.
能夠看到, forEach函數並不關心fn裏面的具體實現. fn裏面的邏輯也不會被forEach函數的改寫影響.
forEach = function( ary, fn ){ for ( var i = 0, l = ary.length; i < l; i++ ){ var c = ary[ i ]; if ( fn.call( c, i, c ) === false ){ return false; } } }
外觀模式提供一個高層接口,這個接口使得客戶端或子系統更加方便調用。
var stopEvent = function( e ){ //同時阻止事件默認行爲和冒泡 e.stopPropagation(); e.preventDefault(); }
GOF官方定義: 訪問者模式是表示一個做用於某個對象結構中的各元素的操做。它使能夠在不改變各元素的類的前提下定義做用於這些元素的新操做。咱們在使用一些操做對不一樣的對象進行處理時,每每會根據不一樣的對象選擇不一樣的處理方法和過程。在實際的代碼過程當中,咱們能夠發現,若是讓全部的操做分散到各個對象中,整個系統會變得難以維護和修改。且增長新的操做一般都要從新編譯全部的類。所以,爲了解決這個問題,咱們能夠將每個類中的相關操做提取出來,包裝成一個獨立的對象,這個對象咱們就稱爲訪問者(Visitor)。利用訪問者,對訪問的元素進行某些操做時,只需將此對象做爲參數傳遞給當前訪問者,而後,訪問者會依據被訪問者的具體信息,進行相關的操做。
策略模式的意義是定義一系列的算法,把它們一個個封裝起來,而且使它們可相互替換。
中介者對象可讓各個對象之間不須要顯示的相互引用,從而使其耦合鬆散,並且能夠獨立的改變它們之間的交互。
迭代器模式提供一種方法順序訪問一個聚合對象中各個元素,而又不須要暴露該方法中的內部表示。
js中咱們常常會封裝一個each函數用來實現迭代器。
組合模式又叫部分-總體模式,它將全部對象組合成樹形結構。使得用戶只須要操做最上層的接口,就能夠對全部成員作相同的操做。
備忘錄模式在js中常常用於數據緩存. 好比一個分頁控件, 從服務器得到某一頁的數據後能夠存入緩存。之後再翻回這一頁的時候,能夠直接使用緩存裏的數據而無需再次請求服務器。
HTTP:
是互聯網上應用最爲普遍的一種網絡協議,是一個客戶端和服務器端請求和應答的標準(TCP),用於從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議,它能夠使瀏覽器更加高效,使網絡傳輸減小。
HTTPS:
是以安全爲目標的HTTP通道,簡單講是HTTP的安全版,即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。HTTPS協議的主要做用能夠分爲兩種:一種是創建一個信息安全通道,來保證數據傳輸的安全;另外一種就是確認網站的真實性。
區別:
一、https協議須要到ca申請證書,通常免費證書較少,於是須要必定費用。
二、http是超文本傳輸協議,信息是明文傳輸,https則是具備安全性的ssl加密傳輸協議。
三、http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443。
四、http的鏈接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
HTTPS工做原理
客戶端發起HTTPS請求->服務端配置(採用HTTPS協議的服務器必需要有一套本身的的數據證書) ->傳送證書(至關於公鑰) ->客戶端解析證書(由客戶端TLS完成,驗證公鑰是否有效,如沒有問題就生成一個隨機值,而後用證書加密) ->傳送加密信息(傳送用證書加密後的隨機值,至關於客戶端與服務端通訊的鑰匙)->服務端解密信息(服務端用私鑰解密隨機值,並對請求內容經過該值進行對稱加密) ->傳輸加密後的信息->客戶端解密信息(客戶端用以前生成的私鑰解密服務端傳回來的信息)
創建鏈接過程:
HTTPS 優勢:
1.SEO方面
2.安全性
(1)、使用HTTPS協議可認證用戶和服務器,確保數據發送到正確的客戶機和服務器;
(2)、HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,要比http協議安全,可防止數據在傳輸過程當中不被竊取、改變,確保數據的完整性。
(3)、HTTPS是現行架構下最安全的解決方案,雖然不是絕對安全,但它大幅增長了中間人攻擊的成本。
HTTPS的缺點
1.SEO方面
2.經濟方面
(1)、SSL證書須要錢,功能越強大的證書費用越高,我的網站、小網站沒有必要通常不會用。
(2)、SSL證書一般須要綁定IP,不能在同一IP上綁定多個域名,IPv4資源不可能支撐這個消耗(SSL有擴展能夠部分解決這個問題,可是比較麻煩,並且要求瀏覽器、操做系統支持,Windows XP就不支持這個擴展,考慮到XP的裝機量,這個特性幾乎沒用)。
(3)、HTTPS鏈接緩存不如HTTP高效,大流量網站如非必要也不會採用,流量成本過高。
(4)、HTTPS鏈接服務器端資源佔用高不少,支持訪客稍多的網站須要投入更大的成本,若是所有采用HTTPS,基於大部分計算資源閒置的假設的VPS的平均成本會上去。
(5)、HTTPS協議握手階段比較費時,對網站的相應速度有負面影響,如非必要,沒有理由犧牲用戶體驗
100 Continue 繼續,通常在發送post請求時,已發送了http header以後服務端將返回此信息,表示確認,以後發送具體參數信息
200 OK 正常返回信息
201 Created 請求成功而且服務器建立了新的資源
202 Accepted 服務器已接受請求,但還沒有處理
301 Moved Permanently 請求的網頁已永久移動到新位置。
302 Found 臨時性重定向。
303 See Other 臨時性重定向,且老是使用 GET 請求新的 URI。
304 Not Modified 自從上次請求後,請求的網頁未修改過。
400 Bad Request 服務器沒法理解請求的格式,客戶端不該當嘗試再次使用相同的內容發起請求。
401 Unauthorized 請求未受權。
403 Forbidden 禁止訪問。
404 Not Found 找不到如何與 URI 相匹配的資源。
500 Internal Server Error 最多見的服務器端錯誤。
503 Service Unavailable 服務器端暫時沒法處理請求(多是過載或維護)。
關於緩存的使用這裏介紹兩套方案:expires/If-Modified-Since、Cache-Control/Etag;前者是HTTP1.0中的緩存方案,後者是HTTP1.1中緩存方案,若http頭部中同時出現兩者,後者的優先級更高。
Expires 和 max-age 均可以用來指定文檔的過時時間,可是兩者有一些細微差異
2.1客戶端和服務器時間不一樣步致使Expires的配置出現問題。
2.2很容易在配置後忘記具體的過時時間,致使過時來臨出現浪涌現象
它分爲強緩存和協商緩存:
1)瀏覽器在加載資源時,先根據這個資源的一些http header判斷它是否命中強緩存,強緩存若是命中,瀏覽器直接從本身的緩存中讀取資源,不會發請求到服務器。好比某個css文件,若是瀏覽器在加載它所在的網頁時,這個css文件的緩存配置命中了強緩存,瀏覽器就直接從緩存中加載這個css,連請求都不會發送到網頁所在服務器;
2)當強緩存沒有命中的時候,瀏覽器必定會發送一個請求到服務器,經過服務器端依據資源的另一些http header驗證這個資源是否命中協商緩存,若是協商緩存命中,服務器會將這個請求返回,可是不會返回這個資源的數據,而是告訴客戶端能夠直接從緩存中加載這個資源,因而瀏覽器就又會從本身的緩存中去加載這個資源;
3)強緩存與協商緩存的共同點是:若是命中,都是從客戶端緩存中加載資源,而不是從服務器加載資源數據;區別是:強緩存不發請求到服務器,協商緩存會發請求到服務器。
4)當協商緩存也沒有命中的時候,瀏覽器直接從服務器加載資源數據。
強緩存
是利用Expires或者Cache-Control這兩個http response header實現的,它們都用來表示資源在客戶端緩存的有效期。
緩存原理是:
1)瀏覽器第一次跟服務器請求一個資源,服務器在返回這個資源的同時,在respone的header加上Expires的header,如:
2)瀏覽器在接收到這個資源後,會把這個資源連同全部response header一塊兒緩存下來(因此緩存命中的請求返回的header並非來自服務器,而是來自以前緩存的header);
3)瀏覽器再請求這個資源時,先從緩存中尋找,找到這個資源後,拿出它的Expires跟當前的請求時間比較,若是請求時間在Expires指定的時間以前,就能命中緩存,不然就不行。
4)若是緩存沒有命中,瀏覽器直接從服務器加載資源時,Expires Header在從新加載的時候會被更新。
Expires是較老的強緩存管理header,因爲它是服務器返回的一個絕對時間,在服務器時間與客戶端時間相差較大時,緩存管理容易出現問題,好比隨意修改下客戶端時間,就能影響緩存命中的結果。因此在http1.1的時候,提出了一個新的header,就是Cache-Control,這是一個相對時間,在配置緩存的時候,以秒爲單位,用數值表示,如:Cache-Control:max-age=315360000,它的緩存原理是:(與 expires相似)
Cache-Control描述的是一個相對時間,在進行緩存命中的時候,都是利用客戶端時間進行判斷,因此相比較Expires,Cache-Control的緩存管理更有效,安全一些。
這兩個header能夠只啓用一個,也能夠同時啓用,當response header中,Expires和Cache-Control同時存在時,Cache-Control優先級高於Expires:
強緩存的應用
強緩存是前端性能優化最有力的工具,沒有之一,對於有大量靜態資源的網頁,必定要利用強緩存,提升響應速度。一般的作法是,爲這些靜態資源所有配置一個超時時間超長的Expires或Cache-Control,這樣用戶在訪問網頁時,只會在第一次加載時從服務器請求靜態資源,其它時候只要緩存沒有失效而且用戶沒有強制刷新的條件下都會從本身的緩存中加載,好比前面提到過的京東首頁緩存的資源,它的緩存過時時間都設置到了2026年:
然而這種緩存配置方式會帶來一個新的問題,就是發佈時資源更新的問題,好比某一張圖片,在用戶訪問第一個版本的時候已經緩存到了用戶的電腦上,當網站發佈新版本,替換了這個圖片時,已經訪問過第一個版本的用戶因爲緩存的設置,致使在默認的狀況下不會請求服務器最新的圖片資源,除非他清掉或禁用緩存或者強制刷新,不然就看不到最新的圖片效果。
協商緩存
當瀏覽器對某個資源的請求沒有命中強緩存,就會發一個請求到服務器,驗證協商緩存是否命中,若是協商緩存命中,請求響應返回的http狀態爲304而且會顯示一個Not Modified的字符串,好比你打開京東的首頁,按f12打開開發者工具,再按f5刷新頁面,查看network,能夠看到有很多請求就是命中了協商緩存的:
查看單個請求的Response Header,也能看到304的狀態碼和Not Modified的字符串,只要看到這個就可說明這個資源是命中了協商緩存,而後從客戶端緩存中加載的,而不是服務器最新的資源:
協商緩存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】這兩對Header來管理的。
**【Last-Modified,If-Modified-Since】**的控制緩存的原理是:
1)瀏覽器第一次跟服務器請求一個資源,服務器在返回這個資源的同時,在respone的header加上Last-Modified的header,這個header表示這個資源在服務器上的最後修改時間:
2)瀏覽器再次跟服務器請求這個資源時,在request的header上加上If-Modified-Since的header,這個header的值就是上一次請求時返回的Last-Modified的值:
3)服務器再次收到資源請求時,根據瀏覽器傳過來If-Modified-Since和資源在服務器上的最後修改時間判斷資源是否有變化,若是沒有變化則返回304 Not Modified,可是不會返回資源內容;若是有變化,就正常返回資源內容。當服務器返回304 Not Modified的響應時,response header中不會再添加Last-Modified的header,由於既然資源沒有變化,那麼Last-Modified也就不會改變,這是服務器返回304時的response header:
4)瀏覽器收到304的響應後,就會從緩存中加載資源。
5)若是協商緩存沒有命中,瀏覽器直接從服務器加載資源時,Last-Modified Header在從新加載的時候會被更新,下次請求時,If-Modified-Since會啓用上次返回的Last-Modified值。
【Last-Modified,If-Modified-Since】都是根據服務器時間返回的header,通常來講,在沒有調整服務器時間和篡改客戶端緩存的狀況下,這兩個header配合起來管理協商緩存是很是可靠的,可是有時候也會服務器上資源其實有變化,可是最後修改時間卻沒有變化的狀況,而這種問題又很不容易被定位出來,而當這種狀況出現的時候,就會影響協商緩存的可靠性。因此就有了另一對header來管理協商緩存,這對header就是【ETag、If-None-Match】。它們的緩存管理的方式是:
1)瀏覽器第一次跟服務器請求一個資源,服務器在返回這個資源的同時,在respone的header加上ETag的header,這個header是服務器根據當前請求的資源生成的一個惟一標識,這個惟一標識是一個字符串,只要資源有變化這個串就不一樣,跟最後修改時間沒有關係,因此能很好的補充Last-Modified的問題:
2)瀏覽器再次跟服務器請求這個資源時,在request的header上加上If-None-Match的header,這個header的值就是上一次請求時返回的ETag的值:
3)服務器再次收到資源請求時,根據瀏覽器傳過來If-None-Match和而後再根據資源生成一個新的ETag,若是這兩個值相同就說明資源沒有變化,不然就是有變化;若是沒有變化則返回304 Not Modified,可是不會返回資源內容;若是有變化,就正常返回資源內容。與Last-Modified不同的是,當服務器返回304 Not Modified的響應時,因爲ETag從新生成過,response header中還會把這個ETag返回,即便這個ETag跟以前的沒有變化:
4)瀏覽器收到304的響應後,就會從緩存中加載資源。
協商緩存的管理
協商緩存跟強緩存不同,強緩存不發請求到服務器,因此有時候資源更新了瀏覽器還不知道,可是協商緩存會發請求到服務器,因此資源是否更新,服務器確定知道。大部分web服務器都默認開啓協商緩存,並且是同時啓用【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】,好比apache:
【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】通常都是同時啓用,這是爲了處理Last-Modified不可靠的狀況。有一種場景須要注意:
分佈式系統裏多臺機器間文件的Last-Modified必須保持一致,以避免負載均衡到不一樣機器致使比對失敗;
分佈式系統儘可能關閉掉ETag(每臺機器生成的ETag都會不同);
協商緩存須要配合強緩存使用,你看前面這個截圖中,除了Last-Modified這個header,還有強緩存的相關header,由於若是不啓用強緩存的話,協商緩存根本沒有意義。
其餘:
1)當ctrl+f5強制刷新網頁時,直接從服務器加載,跳過強緩存和協商緩存;
2)當f5刷新網頁時,跳過強緩存,可是會檢查協商緩存;
大公司的靜態資源優化方案,基本上要實現這麼幾個東西:
IP是Internet Protocol的簡稱,是網絡層的主要協議,做用是提供不可靠、無鏈接的數據報傳送。
TCP**:**可靠,穩定 TCP的可靠體如今TCP在傳遞數據以前,會有三次握手來創建鏈接,並且在數據傳遞時,有確認、窗口、重傳、擁塞控制機制,在數據傳完後,還會斷開鏈接用來節約系統資源。TCP的缺點: 慢,效率低,佔用系統資源高,易被攻擊
UDP**:**快,比TCP稍安全 UDP沒有TCP的握手、確認、窗口、重傳、擁塞控制等機制,UDP是一個無狀態的傳輸協議,因此它在傳遞數據時很是快。沒有TCP的這些機制,UDP較TCP被攻擊者利用的漏洞就要少一些。缺點:不可靠,不穩定 由於UDP沒有TCP那些可靠的機制,在數據傳遞時,若是網絡質量很差,就會很容易丟包
常見使用TCP協議的應用以下: 瀏覽器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ文件傳輸
UDP: 當對網絡通信質量要求不高的時候,要求網絡通信速度能儘可能的快,這時就能夠使用UDP。 好比,平常生活中,常見使用UDP協議的應用以下: QQ語音 QQ視頻 TFTP
TCP傳輸的三次握手四次揮手策略
爲了準確無誤地把數據送達目標處,TCP協議採用了三次握手策略。用TCP協議把數據包送出去後,TCP不會對傳送 後的狀況置之不理,它必定會向對方確認是否成功送達。握手過程當中使用了TCP的標誌:SYN和ACK。
發送端首先發送一個帶SYN標誌的數據包給對方。接收端收到後,回傳一個帶有SYN/ACK標誌的數據包以示傳達確認信息。最後,發送端再回傳一個帶ACK標誌的數據包,表明「握手」結束。
若在握手過程當中某個階段莫名中斷,TCP協議會再次以相同的順序發送相同的數據包。
LISTEN
狀態,等待客戶端鏈接請求。SYN-SEND
狀態。SYN-RECEIVED(同步收到)
狀態。ESTABLISHED (已鏈接)
狀態ESTABLISHED
狀態。這樣三次握手創建鏈接的階段就完成了,雙方能夠直接通訊了。
斷開一個TCP鏈接則須要「四次握手」:
企鵝廠比較喜歡問,考察認識的廣度。
應用層:應用層、表示層、會話層(從上往下)(HTTP、FTP、SMTP、DNS)
傳輸層(TCP和UDP)
網絡層(IP)
物理和數據鏈路層(以太網)
每一層的做用以下:
物理層:經過媒介傳輸比特,肯定機械及電氣規範(比特Bit)RJ45 、 CLOCK 、 IEEE802.3 (中繼器,集線器,網關
數據鏈路層:將比特組裝成幀和點到點的傳遞(幀Frame)PPP 、 FR 、 HDLC 、 VLAN 、 MAC (網橋,交換機)
網絡層:負責數據包從源到宿的傳遞和網際互連(包PackeT)IP 、 ICMP 、 ARP 、 RARP 、 OSPF 、 IPX 、 RIP 、 IGRP 、 (路由器)
傳輸層:提供端到端的可靠報文傳遞和錯誤恢復(段Segment)TCP 、 UDP 、 SPX
會話層:創建、管理和終止會話(會話協議數據單元SPDU)NFS 、 SQL 、 NETBIOS 、 RPC
表示層:對數據進行翻譯、加密和壓縮(表示協議數據單元PPDU)JPEG 、 MPEG 、 ASII
應用層:容許訪問OSI環境的手段(應用協議數據單元APDU)FTP 、 DNS 、 Telnet 、 SMTP 、 HTTP 、 WWW 、 NFS
各類協議
ICMP協議: 因特網控制報文協議。它是TCP/IP協議族的一個子協議,用於在IP主機、路由器之間傳遞控制消息。
TFTP協議: 是TCP/IP協議族中的一個用來在客戶機與服務器之間進行簡單文件傳輸的協議,提供不復雜、開銷不大的文件傳輸服務。
HTTP協議: 超文本傳輸協議,是一個屬於應用層的面向對象的協議,因爲其簡捷、快速的方式,適用於分佈式超媒體信息系統。
DHCP協議: 動態主機配置協議,是一種讓系統得以鏈接到網絡上,並獲取所須要的配置參數手段。
流是鏈接中的一個虛擬信道,能夠承載雙向消息傳輸。每一個流有惟一整數標識符。爲了防止兩端流ID衝突,客戶端發起的流具備奇數ID,服務器端發起的流具備偶數ID。
在二進制分幀層上,http2.0會將全部傳輸信息分割爲更小的消息和幀,並對它們採用二進制格式的編碼將其封裝,新增的二進制分幀層同時也可以保證http的各類動詞,方法,首部都不受影響,兼容上一代http標準。其中,http1.X中的首部信息header封裝到Headers幀中,而request body將被封裝到Data幀中。
服務器能夠對一個客戶端請求發送多個響應,服務器向客戶端推送資源無需客戶端明確地請求。而且,服務端推送能把客戶端所須要的資源伴隨着index.html一塊兒發送到客戶端,省去了客戶端重複請求的步驟。
正由於沒有發起請求,創建鏈接等操做,因此靜態資源經過服務端推送的方式能夠極大地提高速度。不過與之相比,服務器推送還有一個很大的優點:能夠緩存!也讓在遵循同源的狀況下,不一樣頁面之間能夠共享緩存資源成爲可能。
當服務端須要主動推送某個資源時,便會發送一個 Frame Type 爲 PUSH\_PROMISE 的 Frame,裏面帶了 PUSH 須要新建的 Stream ID。意思是告訴客戶端:接下來我要用這個 ID 向你發送東西,客戶端準備好接着。客戶端解析 Frame 時,發現它是一個 PUSH\_PROMISE 類型,便會準備接收服務端要推送的流。
在http1.1中,瀏覽器客戶端在同一時間,針對同一域名下的請求有必定數量的限制,超過限制數目的請求會被阻塞。這也是爲什麼一些站點會有多個靜態資源 CDN 域名的緣由之一。
而http2.0中的多路複用優化了這一性能。多路複用容許同時經過單一的http/2 鏈接發起多重的請求-響應消息。有了新的分幀機制後,http/2 再也不依賴多個TCP鏈接去實現多流並行了。每一個數據流都拆分紅不少互不依賴的幀,而這些幀能夠交錯(亂序發送),還能夠分優先級,最後再在另外一端把它們從新組合起來。
http 2.0 鏈接都是持久化的,並且客戶端與服務器之間也只須要一個鏈接(每一個域名一個鏈接)便可。http2鏈接能夠承載數十或數百個流的複用,多路複用意味着來自不少流的數據包可以混合在一塊兒經過一樣鏈接傳輸。當到達終點時,再根據不一樣幀首部的流標識符從新鏈接將不一樣的數據流進行組裝。
http1.x的頭帶有大量信息,並且每次都要重複發送。http/2使用encoder來減小須要傳輸的header大小,通信雙方各自緩存一份頭部字段表,既避免了重複header的傳輸,又減少了須要傳輸的大小。
事實上,若是請求中不包含首部(例如對同一資源的輪詢請求),那麼,首部開銷就是零字節,此時全部首部都自動使用以前請求發送的首部。
若是首部發生了變化,則只需將變化的部分加入到header幀中,改變的部分會加入到頭部字段表中,首部表在 http 2.0 的鏈接存續期內始終存在,由客戶端和服務器共同漸進地更新。
http/2使用的是專門爲首部壓縮而設計的HPACK②算法。(http/2的HPACK算法使用一份索引表來定義經常使用的http Header,把經常使用的 http Header 存放在表裏,請求的時候便只須要發送在表裏的索引位置便可。)
把http消息分爲不少獨立幀以後,就能夠經過優化這些幀的交錯和傳輸順序進一步優化性能。每一個流均可以帶有一個31比特的優先值:0 表示最高優先級;2的31次方-1 表示最低優先級。
●優先級最高:主要的html
●優先級高:CSS文件
●優先級中:js文件
●優先級低:圖片
性能瓶頸
啓用http2.0後會給性能帶來很大的提高,但同時也會帶來新的性能瓶頸。由於如今全部的壓力集中在底層一個TCP鏈接之上,TCP極可能就是下一個性能瓶頸,好比TCP分組的隊首阻塞問題,單個TCP packet丟失致使整個鏈接阻塞,沒法逃避,此時全部消息都會受到影響。將來,服務器端針對http 2.0下的TCP配置優化相當重要。
經常使用六種方法:構造函數繼承、原型鏈繼承、組合繼承、原型式繼承、寄生式繼承
解決了原型繼承中的問題,能夠實現多繼承.
缺點:
實例並非父類的實例,只是子類的實例。只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法。
沒法實現函數複用,每一個子類都有父類實例函數的副本,影響性能。
// 使用 call 或 apply 方法,將父對象的構造函數綁定在子對象上。 function Animal(){ this.species = "動物"; } function Cat(name,color){ Animal.apply(this, arguments); this.name = name; this.color = color; } var cat1 = new Cat("大毛","黃色"); alert(cat1.species); // 動物
缺點:
來自原型對象的引用類屬性是全部實例共享的、
建立子類實例時,沒法向父類構造函數傳參。
Cat.prototype = new Animal(); // 將Cat的prototype對象指向一個Animal的實例 Cat.prototype.constructor = Cat; // 本來指向Cat的構造函數,受上一句的影響Cat.prototype.constructor指向Animal,並且每個實例也有一個constructor屬性,默認調用prototype對象的constructor屬性,這樣會致使繼承鏈的絮亂,所以須要手動糾正,將constructor改回爲Cat. var cat1 = new Cat("大毛","黃色"); alert(cat1.species); // 動物
js 原型、原型鏈概念:原型對象也是普通對象,是對象一個自帶的隱式 proto 屬性,原型也有可能有本身的原型,若是一個原型對象不爲 null 的話,則稱之爲原型鏈。原型鏈是由一些用來繼承和共享屬性的對象組成的(有限的)對象鏈。
解決上面的問題,**但調用了兩次父類構造函數,生成了兩份實例,消耗內存**. function Parent (name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function () { console.log(this.name) } function Child (name, age) { Parent.call(this, name); this.age = age; } Child.prototype = new Parent(); Child.prototype.constructor = Child; var child1 = new Child('kevin', '18');
就是 ES5 Object.create 的模擬實現,將傳入的對象做爲建立的對象的原型。
缺點:
包含引用類型的屬性值始終都會共享相應的值,這點跟原型鏈繼承同樣。
function createObj(o) { function F(){} F.prototype = o; return new F(); }
缺點:跟借用構造函數模式同樣,每次建立對象都會建立一遍方法。
function createObj (o) { var clone = Object.create(o); clone.sayName = function () { console.log('hi'); } return clone; }
這種方式的高效率體現它只調用了一次 Parent 構造函數,而且所以避免了在 Parent.prototype 上面建立沒必要要的、多餘的屬性。與此同時,原型鏈還能保持不變;所以,還可以正常使用 instanceof 和 isPrototypeOf。開發人員廣泛認爲寄生組合式繼承是引用類型最理想的繼承範式。
function Parent (name) { this.name = name; this.colors = ['red', 'blue', 'green']; } Parent.prototype.getName = function () { console.log(this.name) } function Child (name, age) { Parent.call(this, name); this.age = age; } // 關鍵的三步 var F = function () {}; F.prototype = Parent.prototype; Child.prototype = new F(); var child1 = new Child('kevin', '18'); console.log(child1); // 封裝後 function prototype(child, parent) { var pt = Object.create(parent.prototype); pt.constructor = child; child.prototype = pt; } // 當咱們使用的時候: prototype(Child, Parent);
class Animal { constructor(name) { this.name = name } getName() { return this.name } } class Dog extends Animal { constructor(name, age) { super(name) this.age = age } }
this 是在函數被調用時發生的綁定,它指向什麼徹底取決於函數在哪裏被調用。
一般來講,做用域一共有兩種主要的工做模型。
而 JavaScript 就是採用的詞法做用域,也就是在編程階段,做用域就已經明確下來了。
在 JavaScript 中,影響 this 指向的綁定規則有四種:
1.默認綁定,這是最直接的一種方式,就是不加任何的修飾符直接調用函數
2.隱式綁定,這種狀況會發生在調用位置存在「上下文對象」的狀況,如:
3.顯示綁定
這種就是使用 Function.prototype 中的三個方法 call(), apply(), bind() 了。這三個函數,均可以改變函數的 this 指向到指定的對象,不一樣之處在於,call() 和 apply() 是當即執行函數,而且接受的參數的形式不一樣:
bind 與 call、apply 區別:bind返回的是一個函數,須要調用才能執行,call、apply 直接執行
4.new 綁定
在 JavaScript 中,全部的函數均可以被 new 調用,這時候這個函數通常會被稱爲「構造函數」,實際上並不存在所謂「構造函數」,更確切的理解應該是對於函數的「構造調用」。
使用 new 來調用函數,會自動執行下面操做:
**一個例外狀況:**當在構造函數返回一個對象時,內部建立出來的新對象就會被返回的對象所覆蓋。
function Test(name) { this.name = name console.log(this) // Test { name: 'yck' } return { age: 26 } } const t = new Test('yck') console.log(t) // { age: 26 } console.log(t.name) // 'undefined'
優先級順序爲:
「new 綁定」 > 「顯式綁定」 > 「隱式綁定」 > 「默認綁定。」
因此,this 究竟是什麼
this 並非在編寫的時候綁定的,而是在運行時綁定的。它的上下文取決於函數調用時的各類條件。
this 的綁定和函數聲明的位置沒有任何關係,只取決於函數的調用方式。
當一個函數被調用時,會建立一個「執行上下文」,這個上下文會包含函數在哪裏被調用(調用棧)、函數的調用方式、傳入的參數等信息。this 就是這個記錄的一個屬性,會在函數執行的過程當中用到。
var xhr; if (window.XMLHttpRequest) { // IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執行代碼 xhr = new XMLHttpRequest(); } else { // IE6, IE5 瀏覽器執行代碼 xhr = new ActiveXObject("Microsoft.XMLHTTP"); } xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { document.getElementById("myDiv").innerHTML = xhr.responseText; } } xhr.open("GET", "/try/ajax/ajax_info.txt", true); xhr.send();
XHR enctype 屬性規定在發送到服務器以前應該如何對錶單數據進行編碼
ajax 優勢
缺點
ajax
幹掉了back
按鈕和加入收藏書籤功能,即對瀏覽器後退機制的破壞。URL
直接訪問1.jsonp 須要目標服務器配合一個callback函數。
2.window.name+iframe 須要目標服務器響應window.name。
3.window.location.hash+iframe 一樣須要目標服務器做處理。
4.html5的 postMessage+ifrme 這個也是須要目標服務器或者說是目標頁面寫一個postMessage,主要側重於前端通信。
5.CORS須要服務器設置header :Access-Control-Allow-Origin。
6.nginx反向代理 這個方法通常不多有人說起,可是他能夠不用目標服務器配合,不過須要你搭建一箇中轉nginx服務器,用於轉發請求。
同源策略是客戶端腳本(尤爲是Javascript)的重要的安全度量標準。它最先出自Netscape Navigator2.0,其目的是防止某個文檔或腳本從多個不一樣源裝載。
這裏的同源策略指的是:協議,域名,端口相同,同源策略是一種安全協議,指一段腳本只能讀取來自同一來源的窗口和文檔的屬性。
爲何要有同源限制:
咱們舉例說明:好比一個黑客程序,他利用Iframe把真正的銀行登陸頁面嵌到他的頁面上,當你使用真實的用戶名,密碼登陸時,他的頁面就能夠經過Javascript讀取到你的表單中input中的內容,這樣用戶名,密碼就輕鬆到手了。
get post 區別
get比post更不安全,由於參數直接暴露在url中,因此不能用來傳遞敏感信息。
對於GET方式的請求,瀏覽器會把http header和data一併發送出去,服務器響應200(返回數據);
而對於POST,瀏覽器先發送header,服務器響應100 continue,瀏覽器再發送data,服務器響應200 ok(返回數據)。
從做用域鏈講起
首先明確幾個概念:
閉包的特性
閉包的主要特性就是能夠從外部訪問函數內部的屬性和方法。
閉包的用途
利用閉包強大的特性,最方便的用途就是實現私有變量和私有方法;另外,由於使用閉包會在內存中保存函數做用域,所以也能保存變量的值。
閉包致使的問題
js setTimeout 閉包問題,連續打印出12345
與JS中的垃圾回收機制有關,有兩種策略來實現垃圾回收:標記清除和引用計數。
引用計數:
**早期的回收算法,就是先記下某個變量被引用的總次數,而後當被引用次數爲0時,就表示可回收。**問題在於對於根部不可訪問即脫離環境的仍存在相互引用的狀況,它們的引用次數不爲 0,就不能被回收。
標記清除
一些優化:
什麼是垃圾?
通常來講沒有被引用的對象就是垃圾,就是要被清除, 有個例外若是幾個對象引用造成一個環,互相引用,但根訪問不到它們,這幾個對象也是垃圾,也要被清除。
JS箭頭函數和function的區別:
由於箭頭函數沒有 this,因此一切試圖改變箭頭函數this指向都會是無效的,箭頭函數的this只取決於定義時的環境。
Promise
是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最先提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise
對象。有了Promise
對象,就能夠將異步操做以同步操做的流程表達出來,避免了層層嵌套的回調函數。此外,Promise
對象提供統一的接口,使得控制異步操做更加容易。
Promise
有三種狀態pending
,resolved
和rejected
。狀態轉換隻能是pending
到resolved
或者pending
到rejected
;狀態一旦轉換完成,不能再次轉換。Promise
擁有一個then
方法,用以處理resolved
或rejected
狀態下的值。實現
class Promise { // 定義Promise狀態變量,初始值爲pending status = 'pending'; // 由於在then方法中須要處理Promise成功或失敗時的值,因此須要一個全局變量存儲這個值 data = ''; // Promise resolve時的回調函數集 onResolvedCallback = []; // Promise reject時的回調函數集 onRejectedCallback = []; // Promise構造函數,傳入參數爲一個可執行的函數 constructor(executor) { // resolve函數負責把狀態轉換爲resolved function resolve(value) { this.status = 'resolved'; this.data = value; for (const func of this.onResolvedCallback) { func(this.data); } } // reject函數負責把狀態轉換爲rejected function reject(reason) { this.status = 'rejected'; this.data = reason; for (const func of this.onRejectedCallback) { func(this.data); } } // 直接執行executor函數,參數爲處理函數resolve, reject。由於executor執行過程有可能會出錯,錯誤狀況須要執行reject try { executor(resolve, reject); } catch(e) { reject(e) } } /** * 擁有一個then方法 * then方法提供:狀態爲resolved時的回調函數onResolved,狀態爲rejected時的回調函數onRejected * 返回一個新的Promise */ then(onResolved, onRejected) { // 設置then的默認參數,默認參數實現Promise的值的穿透 onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return e }; onRejected = typeof onRejected === 'function' ? onRejected : function(e) { throw e }; let promise2; promise2 = new Promise((resolve, reject) => { // 若是狀態爲resolved,則執行onResolved if (this.status === 'resolved') { setTimeout(() => { try { // onResolved/onRejected有返回值則把返回值定義爲x const x = onResolved(this.data); // 執行[[Resolve]](promise2, x) this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); } // 若是狀態爲rejected,則執行onRejected if (this.status === 'rejected') { setTimeout(() => { try { const x = onRejected(this.data); this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); } // 若是狀態爲pending,則把處理函數進行存儲 if (this.status = 'pending') { this.onResolvedCallback.push(() => { setTimeout(() => { try { const x = onResolved(this.data); this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); this.onRejectedCallback.push(() => { setTimeout(() => { try { const x = onRejected(this.data); this.resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }, 0); }); } }); return promise2; } // [[Resolve]](promise2, x)函數 resolvePromise(promise2, x, resolve, reject) { ... //簡易版 // 若是x仍然爲Promise的狀況 if (x instanceof Promise) { // 若是x的狀態尚未肯定,那麼它是有可能被一個thenable決定最終狀態和值,因此須要繼續調用resolvePromise if (x.status === 'pending') { x.then(function(value) { resolvePromise(promise2, value, resolve, reject) }, reject) } else { // 若是x狀態已經肯定了,直接取它的狀態 x.then(resolve, reject) } return } else { resolve(x) } ... } }
核心極簡板20行
function Promise(fn) { this.cbs = []; const resolve = (value) => { setTimeout(() => { this.data = value; this.cbs.forEach((cb) => cb(value)); }); } fn(resolve); } Promise.prototype.then = function (onResolved) { return new Promise((resolve) => { this.cbs.push(() => { const res = onResolved(this.data); if (res instanceof Promise) { res.then(resolve); } else { resolve(res); } }); }); };
Promise的一些靜態方法Promise.deferred
、Promise.all
、Promise.race
、Promise.resolve
、Promise.reject
等
Promise.all
方法接收一個promise
數組,返回一個新promise2
,併發執行數組中的所有promise
,全部promise
狀態都爲resolved
時,promise2
狀態爲resolved
並返回所有promise
結果,結果順序和promise
數組順序一致。若是有一個promise
爲rejected
狀態,則整個promise2
進入rejected
狀態。Promise.race
方法接收一個promise
數組, 返回一個新promise2
,順序執行數組中的promise
,有一個promise
狀態肯定,promise2
狀態即肯定,而且同這個promise
的狀態一致。Promise.resolve
用來生成一個rejected
完成態的promise
,Promise.reject
用來生成一個rejected
失敗態的promise
。// Promise.all Promise.all = function(promiseArr) { let index = 0, result = [] return new Promise((resolve, reject) => { promiseArr.forEach((p, i) => { Promise.resolve(p).then(val => { index++ result[i] = val if (index === promiseArr.length) { resolve(result) } }, err => { reject(err) }) }) }) }
Promise存在哪些缺點。
一、沒法取消Promise
,一旦新建它就會當即執行,沒法中途取消。
二、若是不設置回調函數,Promise
內部拋出的錯誤,不會反應到外部。
三、吞掉錯誤或異常,錯誤只能順序處理,即使在Promise
鏈最後添加catch
方法,依然可能存在沒法捕捉的錯誤(catch
內部可能會出現錯誤)
四、閱讀代碼不是一眼能夠看懂,你只會看到一堆then
,必須本身在then
的回調函數裏面理清邏輯。
使用Promise進行順序(sequence)處理。
一、使用async
函數配合await
或者使用generator
函數配合yield
。
二、使用promise.then
經過for
循環或者Array.prototype.reduce
實現。
function sequenceTasks(tasks) { function recordValue(results, value) { results.push(value); return results; } var pushValue = recordValue.bind(null, []); return tasks.reduce(function (promise, task) { return promise.then(() => task).then(pushValue); }, Promise.resolve()); }
Promise鏈上返回的最後一個Promise出錯了怎麼辦?catch
在promise
鏈式調用的末尾調用,用於捕獲鏈條中的錯誤信息,可是catch
方法內部也可能出現錯誤,因此有些promise
實現中增長了一個方法done
,done
至關於提供了一個不會出錯的catch
方法,而且再也不返回一個promise
,通常用來結束一個promise
鏈。
事件代理:就是利用事件冒泡的原理,只指定一個事件處理程序來管理某一類型的全部事件。目的:減小DOM操做,提升性能。原理:事件冒泡中,事件是從最深的節點開始,而後逐步向上傳播事件,那麼咱們給最外面的節點添加事件,那麼子節點被觸發時(如:cilck)都會冒泡到最外層的節點上,因此都會觸發。
事件流****模型:**捕獲型事件和冒泡型事件。**調用事件處理階段-》捕獲-》目標-》冒泡
捕獲性事件應用場景:適用於做全局範圍內的監聽,這裏的全局是相對的全局,相對於某個頂層結點與該結點全部子孫結點造成的集合範圍。
當事件捕獲和事件冒泡一塊兒存在的狀況,事件又是如何觸發呢
requestAnimationFrame 方法讓咱們能夠在下一幀開始時調用指定函數。
以往JS控制的動畫大多使用 setInterval 或者 setTimeout 每隔一段時間刷新元素的位置,來達到動畫的效果,可是這種方式並不能準確地控制動畫幀率,儘管主流的瀏覽器對於這兩個函數實現的動畫都有必定的優化,可是這依然沒法彌補它們性能問題。主要緣由是由於JavaScript的單線程機制使得其可能在有阻塞的狀況下沒法精確到毫秒觸發。
requestAnimationFrame()方法正是爲了知足高性能動畫的需求而提供的API,經過setInterval方法控制的動畫其調用的間隔由程序員設置,而requestAnimationFrame()無須設置調用間隔, 它自動緊跟瀏覽器的繪製的幀率(通常瀏覽器的顯示幀率是60fps,差很少每幀間隔16.7ms)
在實際開發中, 固然儘可能使用css動畫, 畢竟css動畫性能更優。可是對於一些複雜的動畫,好比有暫停,繼續等複雜交互等動畫仍是須要requestAnimationFrame
requestAnimationFrame 無論理回調函數隊列,而滾動、觸摸這類高觸發頻率事件的回調可能會在同一幀內觸發屢次。因此正確使用 requestAnimationFrame 的姿式是,在同一幀內可能調用屢次 requestAnimationFrame時,要管理回調函數,防止重複繪製動畫。
基本數據類型:number, string, boolean, undefined, BigInt, Symbol, null
引用數據類型:Object
對象類型: Array, Function, Map, Set, WeakMap, WeakSet
特殊對象: RegExp, Date
BigInt 類型能夠用任意精度表示整數,能夠安全地存儲和操做大整數
Symbol 符號,符號類型是惟一的而且是不可修改的,能夠用來做爲 Object 的 key 值。
判斷:
typeof
typeof返回一個表示數據類型的字符串,返回結果包括:number、string、boolean、object、undefined、function。typeof能夠對基本類型number、string 、boolean、undefined作出準確的判斷(null除外,typeof null===「object」)而對於引用類型,除了function以外返回的都是object。但當咱們須要知道某個對象的具體類型時,typeof就顯得有些力不從心了。
instanceof
當咱們須要知道某個對象的具體類型時,能夠用運算符 instanceof,instanceof操做符判斷左操做數對象的原型鏈上是否有右邊這個構造函數的prototype屬性,也就是說指定對象是不是某個構造函數的實例,最後返回布爾值。 檢測的咱們用一段僞代碼來模擬instanceof內部執行過程.
function instanceOf(left, right) { let proto = left.__proto__ while (true) { if (proto === null) return false if (proto === right.prototype) { return true } proto = proto.__proto__ } }
constructor
constructor屬性的做用是,能夠得知某個實例對象,究竟是哪個構造函數產生的。可是 constructor 屬性易變,不可信賴,這個主要體如今自定義對象上,當開發者重寫prototype後,原有的constructor會丟失。
Object.prototype.toString
toString是Object原型對象上的一個方法,該方法默認返回其調用者的具體類型,更嚴格的講,是 toString運行時this指向的對象類型, 返回的類型格式爲[object,xxx],xxx是具體的數據類型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上全部對象的類型均可以經過這個方法獲取到。
類型轉換
**轉布爾值規則:**undefined、null、false、NaN、''、0、-0都會轉換爲 false;
其餘全部制都轉爲 true,包括全部對象。
**轉數字規則:**true 爲1,false、null爲0,undefined 爲 NaN, symbol 報錯,
字符串若是是數字或者進制值就轉爲數字,不然就 NaN
四則運算中:
只有當加法運算中,其中一方是字符串類型,就會把另外一個也轉換爲字符串類型
其餘運算中,只要其中一方是數字,那麼另外一方就轉化爲數字。
常見
[] == ![]; // true 5 + '1' = '51' 5 - '1' = 4
可繼承的樣式:
1.font-size 2.font-family
3.color 4.text-indent
不可繼承的樣式:
1.border 2.padding
3.margin 4.width 5.height
優先級算法:
1.優先級就近原則,同權重狀況下樣式定義最近者爲準;
2.載入樣式以最後載入的定位爲準;
3.!important > id > class > tag
4.important 比 內聯優先級高,但內聯比 id 要高
CSS3新增僞類舉例:
p:first-of-type 選擇屬於其父元素的首個
元素的每一個
元素。
p:last-of-type 選擇屬於其父元素的最後
元素的每一個
元素。
p:only-of-type 選擇屬於其父元素惟一的
元素的每一個
元素。
p:only-child 選擇屬於其父元素的惟一子元素的每一個
元素。
p:nth-child(2) 選擇屬於其父元素的第二個子元素的每一個
元素。
:enabled :disabled 控制表單控件的禁用狀態。
:checked 單選框或複選框被選中
BFC,塊級格式化上下文,一個建立了新的BFC的盒子是獨立佈局的,盒子裏面的子元素的樣式不會影響到外面的元素。在同一個 BFC 中的兩個毗鄰的塊級盒在垂直方向(和佈局方向有關係)的 margin 會發生摺疊。
它決定了元素如何對其內容進行定位,以及與其餘元素的關係和相互做用。當涉及到可視化佈局的時候,Block Formatting Context提供了一個環境,HTML元素在這個環境中按照必定規則進行佈局。一個環境中的元素不會影響到其它環境中的佈局。好比浮動元素會造成BFC,浮動元素內部子元素的主要受該浮動元素影響,兩個浮動元素之間是互不影響的。也能夠說BFC就是一個做用範圍。
IFC(Inline Formatting Context)即行內格式化上下文
如何產生BFC
當一個HTML元素知足下面條件的任何一點,均可以產生Block Formatting Context:
a、float的值不爲none
b、overflow的值不爲visible
c、display的值爲table-cell, table-caption, inline-block中的任何一個
d、position的值不爲relative和static
CSS3觸發BFC方式則能夠簡單描述爲:在元素定位非static,relative的狀況下觸發,float也是一種定位方式。
(3)、BFC的做用與特色
a、不和浮動元素重疊,清除外部浮動,阻止浮動元素覆蓋
若是一個浮動元素後面跟着一個非浮動的元素,那麼就會產生一個重疊的現象。常規流(也稱標準流、普通流)是一個文檔在被顯示時最多見的佈局形態,當float不爲none時,position爲absolute、fixed時元素將脫離標準流。
cm
釐米(Centimeters)mm
毫米(Millimeters)q
1/4毫米(quarter-millimeters)in
英寸(Inches)pt
點、磅(Points)pc
派卡(Picas),至關於我國新四號鉛字的尺寸px
em
,ex
,ch
,rem
,vw
相對於視口的寬度,視口被均分爲100單位的vwvh
相對於視口的高度。視口被均分爲100單位的vhvmax
,vmin
em 與 rem的區別
rem是CSS3新增的一個相對單位(root em,根em),相對於根元素(即html元素)font-size計算值的倍數,只相對於根元素的大小 。rem(font size of the root element)是指相對於根元素的字體大小的單位。簡單的說它就是一個相對單位。
做用:利用rem能夠實現簡單的響應式佈局,能夠利用html元素中字體的大小與屏幕間的比值設置font-size的值實現當屏幕分辨率變化時讓元素也變化,之前的天貓tmall就使用這種辦法
文本相對長度單位。相對於當前對象內文本的字體尺寸。如當前對行內文本的字體尺寸未被人爲設置,則相對於瀏覽器的默認字體尺寸(默認16px)。(相對父元素的字體大小倍數)
em(font size of the element)是指相對於父元素的字體大小的單位。它與rem之間其實很類似,區別在。(相對是的HTML元素的字體大,默認16px)
em與rem的重要區別: 它們計算的規則一個是依賴父元素另外一個是依賴根元素計算
使用css佈局position很是重要,語法以下:
position:static | relative | absolute | fixed | center | page | sticky
默認值:static,center、page、sticky是CSS3中新增長的值。
能夠認爲靜態的,默認元素都是靜態的定位,對象遵循常規流。此時4個定位偏移屬性不會被應用,也就是使用left,right,bottom,top將不會生效。
相對定位,對象遵循常規流,而且參照自身在常規流中的位置經過top,right,bottom,left這4個定位偏移屬性進行偏移時不會影響常規流中的任何元素。
a、絕對定位,對象脫離常規流,此時偏移屬性參照的是離自身最近的定位祖先元素,若是沒有定位的祖先元素,則一直回溯到body元素。盒子的偏移位置不影響常規流中的任何元素,其margin不與其餘任何margin摺疊。
b、元素定位參考的是離自身最近的定位祖先元素,要知足兩個條件,第一個是本身的祖先元素,能夠是父元素也能夠是父元素的父元素,一直找,若是沒有則選擇body爲對照對象。第二個條件是要求祖先元素必須定位,通俗說就是position的屬性值爲非static都行。
固定定位,與absolute一致,但偏移定位是以窗口爲參考。當出現滾動條時,對象不會隨着滾動。
與absolute一致,但偏移定位是以定位祖先元素的中心點爲參考。盒子在其包含容器垂直水平居中。(CSS3)
與absolute一致。元素在分頁媒體或者區域塊內,元素的包含塊始終是初始包含塊,不然取決於每一個absolute模式。(CSS3)
對象在常態時遵循常規流。它就像是relative和fixed的合體,當在屏幕中時按常規流排版,當捲動到屏幕外時則表現如fixed。該屬性的表現是現實中你見到的吸附效果。(CSS3)
水平居中
垂直居中
垂直水平居中
.div0{ width:200px; height:150px; border:1px solid #000; line-height:150px; text-align:center; } .redbox{ display:inline-block; width:30px; height:30px; background:#c00; }
.div0::before{ content:''; width:0; height:100%; display:inline-block; position:relative; vertical-align:middle; background:#f00; }
.redbox{ width:30px; height:30px; background:#c00; float:left; top:calc(50% - 15px); margin-left:calc(50% - 45px); }
.use-absolute{ position: relative; width:200px; height:150px; border:1px solid #000; } .use-absolute div{ position: absolute; width:100px; height:50px; top:0; right:0; bottom:0; left:0; margin:auto; background:#f60; }
flexbox: 使用align-items或align-content的屬性
方式:雙飛翼、多欄、彈性、流式、瀑布流、響應式佈局
經典三列布局,也叫作聖盃佈局【Holy Grail of Layouts】是Kevin Cornell在2006年提出的一個佈局模型概念,在國內最先是由淘寶UED的工程師傳播開來,在中國也有叫法是雙飛翼佈局,它的佈局要求有幾點:
a、三列布局,中間寬度自適應,兩邊定寬;
b、中間欄要在瀏覽器中優先展現渲染;
c、容許任意列的高度最高;
d、要求只用一個額外的DIV標籤;
e、要求用最簡單的CSS、最少的HACK語句;
在不增長額外標籤的狀況下,聖盃佈局已經很是完美,聖盃佈局使用了相對定位,之後佈局是有侷限性的,並且寬度控制要改的地方也多。在淘寶UED(User Experience Design)探討下,增長多一個div就能夠不用相對佈局了,只用到了浮動和負邊距,這就是咱們所說的雙飛翼佈局。
a、欄柵格系統:就是利用浮動實現的多欄佈局,在bootstrap中用的很是多。
b、多列布局:柵格系統並無真正實現分欄效果(如word中的分欄),CSS3爲了知足這個要求增長了多列布局模塊
CSS3引入了一種新的佈局模式——Flexbox佈局,即伸縮佈局盒模型(Flexible Box),用來提供一個更加有效的方式制定、調整和分佈一個容器裏項目佈局,即便它們的大小是未知或者動態的,這裏簡稱爲Flex。Flexbox佈局經常使用於設計比較複雜的頁面,能夠輕鬆的實現屏幕和瀏覽器窗口大小發生變化時保持元素的相對位置和大小不變,同時減小了依賴於浮動佈局實現元素位置的定義以及重置元素的大小。
Flexbox佈局在定義伸縮項目大小時伸縮容器會預留一些可用空間,讓你能夠調節伸縮項目的相對大小和位置。例如,你能夠確保伸縮容器中的多餘空間平均分配多個伸縮項目,固然,若是你的伸縮容器沒有足夠大的空間放置伸縮項目時,瀏覽器會根據必定的比例減小伸縮項目的大小,使其不溢出伸縮容器。
綜合而言,Flexbox佈局功能主要具備如下幾點:
a、屏幕和瀏覽器窗口大小發生改變也能夠靈活調整佈局;
b、能夠指定伸縮項目沿着主軸或側軸按比例分配額外空間(伸縮容器額外空間),從而調整伸縮項目的大小;
c、能夠指定伸縮項目沿着主軸或側軸將伸縮容器額外空間,分配到伸縮項目以前、以後或之間;
d、能夠指定如何將垂直於元素佈局軸的額外空間分佈到該元素的周圍;
e、能夠控制元素在頁面上的佈局方向;
f、能夠按照不一樣於文檔對象模型(DOM)所指定排序方式對屏幕上的元素從新排序。也就是說能夠在瀏覽器渲染中不按照文檔流前後順序重排伸縮項目順序。
瀑布流佈局是流式佈局的一種。是當下比較流行的一種網站頁面佈局,視覺表現爲良莠不齊的多欄佈局,隨着頁面滾動條向下滾動,這種佈局還會不斷加載數據塊並附加至當前尾部。最先採用此佈局的網站是Pinterest,逐漸在國內流行開來。
優勢
a、有效的下降了界面複雜度,節省了空間:咱們再也不須要臃腫複雜的頁碼導航連接或按鈕了。
b、對觸屏設備來講,交互方式更符合直覺:在移動應用的交互環境當中,經過向上滑動進行滾屏的操做已經成爲最基本的用戶習慣,並且所須要的操做精準程度遠遠低於點擊連接或按鈕。
c、更高的參與度:以上兩點所帶來的交互便捷性能夠使用戶將注意力更多的集中在內容而不是操做上,從而讓他們更樂於沉浸在探索與瀏覽當中。
缺點
a、有限的用例:無限滾動的方式只適用於某些特定類型產品當中一部分特定類型的內容。 例如,在電商網站當中,用戶時常須要在商品列表與詳情頁面之間切換,這種狀況下,傳統的、帶有頁碼導航的方式能夠幫助用戶更穩妥和準確的回到某個特定的列表頁面當中。
b、額外的複雜度:那些用來打造無限滾動的JS庫雖然都自稱很容易使用,但你總會須要在本身的產品中進行不一樣程度的定製化處理,以知足大家本身的需求;另外這些JS庫在瀏覽器和設備兼容性等方面的表現也良莠不齊,你必須作好充分的測試與調整工做。
c、再見了,頁腳:若是使用了比較典型的無限滾動加載模式,這就意味着你能夠和頁腳說拜拜了。 最好考慮一下頁腳對於你的網站,特別是用戶的重要性;若是其中確實有比較重要的內容或連接,那麼最好換一種更傳統和穩妥的方式。千萬不要耍弄你的用戶,當他們一次次的瀏覽到頁面底部,看到頁腳,卻由於自動加載的內容忽然出現而不管如何都沒法點擊頁腳中的連接時,他們會變的愈加憤怒。
d、集中在一頁當中動態加載數據,與一頁一頁的輸出相比,究竟那種方式更利於SEO,這是你必須考慮的問題。對於某些以類型網站來講,在這方面進行冒險是很不划算的。
e、關於頁面數量的印象:其實站在用戶的角度來看,這一點並不是負面;不過,若是對於你的網站來講,經過更多的內容頁面展現更多的相關信息(包括廣告)是很重要的策略,那麼單頁無限滾動的方式對你並不適用。
固定佈局和流式佈局在網頁設計中最經常使用的兩種佈局方式。固定佈局能呈現網頁的原始設計效果,流式佈局則不受窗口寬度影響,流式佈局使用百分比寬度來限定佈局元素,這樣能夠根據客戶端分辨率的大小來進行合理的顯示。
響應式佈局是Ethan Marcotte在2010年5月份提出的一個概念,簡而言之,就是一個網站可以兼容多個終端——而不是爲每一個終端作一個特定的版本。這個概念是爲解決移動互聯網瀏覽而誕生的。響應式佈局能夠爲不一樣終端的用戶提供更加溫馨的界面和更好的用戶體驗,並且隨着目前大屏幕移動設備的普及,用「大勢所趨」來形容也不爲過。隨着愈來愈多的設計師採用這個技術,咱們不只看到不少的創新,還看到了一些成形的模式。
優勢
a、面對不一樣分辨率設備靈活性強
b、可以快捷解決多設備顯示適應問題
缺點
a、兼容各類設備工做量大,效率低下
b、代碼累贅,會出現隱藏無用的元素,加載時間加長
c、其實這是一種折中性質的設計解決方案,多方面因素影響而達不到最佳效果
d、必定程度上改變了網站原有的佈局結構,會出現用戶混淆的狀況
兩欄佈局,左側定寬,右側自適應
<div id="wrapper1"> <div class="left"> 左邊固定寬度,高度不固定 </br> </br></br></br>高度有可能會很小,也可能很大。 </div> <div class="main"> 這裏的內容可能比左側高,也可能比左側低。寬度須要自適應。</br> 基本的樣式是,兩個div相距20px, 左側div寬 120px </div> </div>
1.雙 inline-block 方法
缺點**:**
#wrapper1 { box-sizing: content-box; border: 1px solid red; padding: 15px 20px; font-size: 0; /*消除空格影響*/ } #wrapper1 .left, .main { box-sizing: border-box; border: 1px solid blue; display: inline-block; font-size: 14px; vertical-align: top; /* 頂端對齊*/ } #wrapper1 .left { width: 200px; } #wrapper1 .main { width: calc(100% - 200px); }
2.雙 float 方法
缺點**:**
#wrapper1 { box-sizing: content-box; border: 1px solid red; padding: 15px 20px; overflow: auto; } #wrapper1 .left, .main { box-sizing: border-box; border: 1px solid blue; float: left; } #wrapper1 .left { width: 200px; } #wrapper1 .main { width: calc(100% - 200px); }
3.使用 float + margin-left 的方法
#wrapper1 { box-sizing: border-box; border: 1px solid red; padding: 15px 20px; overflow: hidden; } #wrapper1 .left, .main { box-sizing: border-box; border: 1px solid blue; } #wrapper1 .left { float: left; } #wrapper1 .main { margin-left: 242px }
4.使用 float + BFC 的方法
缺點**:**
正常流中創建新的塊格式化上下文的元素(例如除'visible'以外的'overflow'的元素)不能與元素自己相同的塊格式上下文中的任何浮點的邊界框重疊。
#wrapper1 { box-sizing: content-box; border: 1px solid red; padding: 15px 20px; overflow: auto; } #wrapper1 .left, .main { box-sizing: border-box; border: 1px solid blue; } #wrapper1 .left { float: left; } #wrapper1 .main { overflow: auto; }
5.使用 flex 方法
須要注意的是,flex容器的一個默認屬性值:align-items: stretch;。這個屬性致使了列等高的效果。 爲了讓兩個盒子高度自動,須要設置: align-items: flex-start;
#wrapper1 { box-sizing: content-box; border: 1px solid red; padding: 15px 20px; display: flex; align-items: flex-start; } #wrapper1 .left, .main { box-sizing: border-box; border: 1px solid blue; } #wrapper1 .left { flex: 0 0 auto; //[ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] } #wrapper1 .main { flex: 1 1 auto; }
6.使用 absulute + margin-left 的方法
缺點**:**
#wrapper1 { box-sizing: border-box; border: 1px solid red; padding: 15px 20px; min-height: 300px; } #wrapper1 .left, .main { box-sizing: border-box; border: 1px solid blue; } #wrapper1 .left { position: absolute; } #wrapper1 .main { margin-left: 242px }
animation: name duration timing-function delay iteration-count direction fill-mode play-state;
( 名稱、長度、如何完成一週期、延遲、次數、是否輪流反向播放、不播放時樣式、動畫播放過程當中可能會忽然中止指定動畫是否正在運行或暫停)
咱們還須要用keyframes關鍵字
@keyframes rainbow { 0% { background: #c00; } 50% { background: orange; } 100% { background: yellowgreen; } }
大體原理是:經過 css3插入一個僞元素,該元素寬度爲父級2倍,高度爲1px,而後經過css3縮放將其縮小一倍,從而實現一個 0.5 px 的邊框。
.content:before { content: ‘’; position:absolute; width:200%; height: 1px; border-bottom: 1px solid #000; transform-origin: 0, 0; -webkit-transform-origin transform: scale(.5,.5); -webkit-transform box-sizing: border-box; -webkit-boxsizing }
#triangle-up { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid red; } |
||
---|---|---|
#triangle-topleft { width: 0; height: 0; border-top: 100px solid red; border-right: 100px solid transparent; } |
//第一種 dom.style.width/height //只能獲取內聯樣式的元素寬高 //第二種 dom.currentStyle.width/height //只有IE瀏覽器支持 //第三種 dom.getComputedStyle(Dom).width/height //只有瀏覽器渲染後才能獲取 兼容好 //第四種 dom.getBoundingClientRect().width/height //計算一個元素的絕對位置(相對於視窗左上角) 能拿到元素的left、right、width、height
Cookie
優勢:
極高的擴展性和可用性
1.經過良好的編程,控制保存在cookie中的session對象的大小。
2.經過加密和安全傳輸技術(SSL),減小cookie被破解的可能性。
3.只在cookie中存放不敏感數據,即便被盜也不會有重大損失。
4.控制cookie的生命期,使之不會永遠有效。偷盜者極可能拿到一個過時的cookie。
缺點:
1.Cookie數量和長度的限制。每一個domain最多隻能有20條cookie,每一個cookie長度不能超過4KB,不然會被截掉。
2.安全性問題。若是cookie被人攔截了,那人就能夠取得全部的session信息。即便加密也與事無補,由於攔截者並不須要知道cookie的意義,他只要原樣轉發cookie就能夠達到目的了。
3.有些狀態不可能保存在客戶端。例如,爲了防止重複提交表單,咱們須要在服務器端保存一個計數器。若是咱們把這個計數器保存在客戶端,那麼它起不到任何做用。
屬性:
name| string : 該Cookie的名稱。Cookie一旦建立,名稱便不可更改
value| object :該Cookie的值。若是值爲Unicode字符,須要爲字符編碼。若是值爲二進制數據,則須要使用BASE64編碼
maxAge| int : 該Cookie失效的時間,單位秒。若是爲正數,則該Cookie在maxAge秒以後失效。若是爲負數,該Cookie爲臨時Cookie,關閉瀏覽器即失效,瀏覽器也不會以任何形式保存該Cookie。若是爲0,表示刪除該Cookie。默認爲–1
secure| boolean : 該Cookie是否僅被使用安全協議傳輸。https,只在使用SSL安全鏈接的狀況下才會把cookie發送到服務器
**path |string:**該Cookie的使用路徑。請求URL中包含這個路徑纔會把cookie發送到服務器。若是設置爲「/sessionWeb/」,則只有contextPath爲「/sessionWeb」的程序能夠訪問該Cookie。若是設置爲「/」,則本域名下contextPath均可以訪問該Cookie。注意最後一個字符必須爲「/」
domain| string : 能夠訪問該Cookie的域名。若是設置爲「.google.com」,則全部以「google.com」結尾的域名均可以訪問該Cookie。注意第一個字符必須爲「.」
comment| string : 該Cookie的用處說明。
version| int : 該Cookie使用的版本號。0表示遵循Netscape的Cookie規範,1表示遵循W3C的RFC 2109規範
**httponly | boolean :**表示此cookie必須用於http或https傳輸。這意味着,瀏覽器腳本,好比javascript中,是不容許訪問操做此cookie的。以防範跨站腳本攻擊(XSS)。
操做:
1.Cookie並不提供修改、刪除操做。若是要修改某個Cookie,只須要新建一個同名的Cookie,添加到response中覆蓋原來的Cookie。
2.若是要刪除某個Cookie,只須要新建一個同名的Cookie,並將maxAge設置爲0,並添加到response中覆蓋原來的Cookie。注意是0而不是負數。負數表明其餘的意義。
永久登陸案例:
LocalStorage
**+**永久存儲
+單個域名存儲量比較大(推薦5MB,各瀏覽器不一樣)
**+**整體數量無限制
SessionStorage
+只在Session內有效
**+**存儲量更大(推薦沒有限制,可是實際上各瀏覽器也不一樣)
主要是關於圖像、位置、存儲、多任務等功能的增長。
移除的元素:
避免手段 若是使用 iframe,最好經過 js 動態給 iframe 添加 src 屬性值。
Canvas | SVG |
---|---|
Canvas是基於像素的位圖,依賴分辨率 | SVG倒是基於矢量圖形,不依賴分辨率 |
Canvas是基於HTML canvas標籤,經過宿主提供的Javascript API對整個畫布進行操做的 | SVG則是基於XML元素的,歷史久遠 |
Canvas沒有圖層的概念,全部的修改整個畫布都要從新渲染 | SVG則能夠對單獨的標籤進行修改 |
關於動畫,Canvas更適合作基於位圖的動畫 | 而SVG則適合圖表的展現 |
不能被引擎抓取 | 能夠被引擎抓取 |
Canvas 可以以 .png 或 .jpg 格式保存結果圖像;可以引入 .png 或 .jpg格式的圖片 | SVG 不能以 .png 或 .jpg 格式保存結果圖像;不能引入 .png 或 .jpg格式的圖片 |
Canvas 不支持事件處理器(一旦圖形被繪製完成,它就不會繼續獲得瀏覽器的關注。若是其位置發生變化,那麼整個場景也須要從新繪製,包括任何或許已被圖形覆蓋的對象。) | SVG 支持事件處理器(SVG DOM 中的每一個元素都是可用的。您能夠爲某個元素附加 JavaScript 事件處理器。每一個被繪製的圖形均被視爲對象。若是 SVG 對象的屬性發生變化,那麼瀏覽器可以自動重現圖形。) |
最適合圖像密集型的遊戲,其中的許多對象會被頻繁重繪 | 不適合遊戲應用 |
script 加載中的 async 與 defer 的區別
DOMContentLoaded, onload
DOMContentLoaded 當初始的 HTML 文檔被徹底加載和解析完成以後,DOMContentLoaded 事件被觸發,而無需等待樣式表、圖像和子框架的完成加載。咱們能夠在這個階段使用 JS 去訪問元素。 async 的腳本可能尚未執行。
document.readyState 表徵頁面的加載狀態,能夠在 readystatechange 中追蹤頁面的變化狀態:
一個http請求絕大多數的時間消耗在了創建鏈接跟等待的時間,優化的方法是減小http請求。
雅虎團隊經驗:網站頁面性能優化的34條黃金守則
一、儘可能減小HTTP請求次數
終端用戶響應的時間中,有80%用於下載各項內容。這部分時間包括下載頁面中的圖像、樣式表、腳本、Flash等。經過減小頁面中的元素能夠減小HTTP請求的次數。這是提升網頁速度的關鍵步驟。
減小頁面組件的方法其實就是簡化頁面設計。那麼有沒有一種方法既能保持頁面內容的豐富性又能達到加快響應時間的目的呢?這裏有幾條減小HTTP請求次數同時又可能保持頁面內容豐富的技術。
合併文件是經過把全部的腳本放到一個文件中來減小HTTP請求的方法,如能夠簡單地把全部的CSS文件都放入一個樣式表中。當腳本或者樣式表在不一樣頁面中使用時須要作不一樣的修改,這可能會相對麻煩點,但即使如此也要把這個方法做爲改善頁面性能的重要一步。
CSS Sprites是減小圖像請求的有效方法。把全部的背景圖像都放到一個圖片文件中,而後經過CSS的background-image和background-position屬性來顯示圖片的不一樣部分;
圖片地圖是把多張圖片整合到一張圖片中。雖然文件的整體大小不會改變,可是能夠減小HTTP請求次數。圖片地圖只有在圖片的全部組成部分在頁面中是緊挨在一塊兒的時候才能使用,如導航欄。肯定圖片的座標和可能會比較繁瑣且容易出錯,同時使用圖片地圖導航也不具備可讀性,所以不推薦這種方法;
內聯圖像是使用data:URL scheme的方法把圖像數據加載頁面中。這可能會增長頁面的大小。把內聯圖像放到樣式表(可緩存)中能夠減小HTTP請求同時又避免增長頁面文件的大小。可是內聯圖像如今尚未獲得主流瀏覽器的支持。
減小頁面的HTTP請求次數是你首先要作的一步。這是改進首次訪問用戶等待時間的最重要的方法。如同Tenni Theurer的他的博客Browser Cahe Usage - Exposed!中所說,HTTP請求在無緩存狀況下佔去了40%到60%的響應時間。讓那些初次訪問你網站的人得到更加快速的體驗吧!
二、減小DNS查找次數
域名系統(DNS)提供了域名和IP的對應關係,就像電話本中人名和他們的電話號碼的關係同樣。當你在瀏覽器地址欄中輸入www.dudo.org時,DNS解析服務器就會返回這個域名對應的IP地址。DNS解析的過程一樣也是須要時間的。通常狀況下返回給定域名對應的IP地址會花費20到120毫秒的時間。並且在這個過程當中瀏覽器什麼都不會作直到DNS查找完畢。
緩存DNS查找能夠改善頁面性能。這種緩存須要一個特定的緩存服務器,這種服務器通常屬於用戶的ISP提供商或者本地局域網控制,可是它一樣會在用戶使用的計算機上產生緩存。DNS信息會保留在操做系統的DNS緩存中(微軟Windows系統中DNS Client Service)。大多數瀏覽器有獨立於操做系統之外的本身的緩存。因爲瀏覽器有本身的緩存記錄,所以在一次請求中它不會受到操做系統的影響。
Internet Explorer默認狀況下對DNS查找記錄的緩存時間爲30分鐘,它在註冊表中的鍵值爲DnsCacheTimeout。Firefox對DNS的查找記錄緩存時間爲1分鐘,它在配置文件中的選項爲network.dnsCacheExpiration(Fasterfox把這個選項改成了1小時)。
當客戶端中的DNS緩存都爲空時(瀏覽器和操做系統都爲空),DNS查找的次數和頁面中主機名的數量相同。這其中包括頁面中URL、圖片、腳本文件、樣式表、Flash對象等包含的主機名。減小主機名的數量能夠減小DNS查找次數。
減小主機名的數量還能夠減小頁面中並行下載的數量。減小DNS查找次數能夠節省響應時間,可是減小並行下載卻會增長響應時間。個人指導原則是把這些頁面中的內容分割成至少兩部分但不超過四部分。這種結果就是在減小DNS查找次數和保持較高程度並行下載二者之間的權衡了。
三、避免跳轉
跳轉是使用301和302代碼實現的。下面是一個響應代碼爲301的HTTP頭:
HTTP/1.1 301 Moved Permanently
Location:http://example.com/newuri
Content-Type: text/html
瀏覽器會把用戶指向到Location中指定的URL。頭文件中的全部信息在一次跳轉中都是必需的,內容部分能夠爲空。無論他們的名稱,301和302響應都不會被緩存除非增長一個額外的頭選項,如Expires或者Cache-Control來指定它緩存。元素的刷新標籤和JavaScript也能夠實現URL的跳轉,可是若是你必需要跳轉的時候,最好的方法就是使用標準的3XXHTTP狀態代碼,這主要是爲了確保「後退」按鈕能夠正確地使用。
可是要記住跳轉會下降用戶體驗。在用戶和HTML文檔中間增長一個跳轉,會拖延頁面中全部元素的顯示,由於在HTML文件被加載前任何文件(圖像、Flash等)都不會被下載。
有一種常常被網頁開發者忽略卻每每十分浪費響應時間的跳轉現象。這種現象發生在當URL本該有斜槓(/)卻被忽略掉時。例如,當咱們要訪問http://astrology.yahoo.com/astrology時,實際上返回的是一個包含301代碼的跳轉,它指向的是http://astrology.yahoo.com/astrology/(注意末尾的斜槓)。在Apache服務器中能夠使用Alias 或者 mod\_rewrite或者the DirectorySlash來避免。
鏈接新網站和舊網站是跳轉功能常常被用到的另外一種狀況。這種狀況下每每要鏈接網站的不一樣內容而後根據用戶的不一樣類型(如瀏覽器類型、用戶帳號所屬類型)來進行跳轉。使用跳轉來實現兩個網站的切換十分簡單,須要的代碼量也很少。儘管使用這種方法對於開發者來講能夠下降複雜程度,可是它一樣下降用戶體驗。一個可替代方法就是若是二者在同一臺服務器上時使用Alias和mod\_rewrite和實現。若是是由於域名的不一樣而採用跳轉,那麼能夠經過使用Alias或者mod\_rewirte創建CNAME(保存一個域名和另一個域名之間關係的DNS記錄)來替代。
四、可緩存的AJAX
Ajax常常被說起的一個好處就是因爲其從後臺服務器傳輸信息的異步性而爲用戶帶來的反饋的即時性。可是,使用Ajax並不能保證用戶不會在等待異步的JavaScript和XML響應上花費時間。在不少應用中,用戶是否須要等待響應取決於Ajax如何來使用。例如,在一個基於Web的Email客戶端中,用戶必須等待Ajax返回符合他們條件的郵件查詢結果。記住一點,「異步」並不異味着「即時」,這很重要。
爲了提升性能,優化Ajax響應是很重要的。提升Ajxa性能的措施中最重要的方法就是使響應具備可緩存性,具體的討論能夠查看Add an Expires or a Cache-Control Header。其它的幾條規則也一樣適用於Ajax:
Gizp壓縮文件
減小DNS查找次數
精簡JavaScript
避免跳轉
配置ETags
讓咱們來看一個例子:一個Web2.0的Email客戶端會使用Ajax來自動完成對用戶地址薄的下載。若是用戶在上次使用過Email web應用程序後沒有對地址薄做任何的修改,並且Ajax響應經過Expire或者Cacke-Control頭來實現緩存,那麼就能夠直接從上一次的緩存中讀取地址薄了。必須告知瀏覽器是使用緩存中的地址薄仍是發送一個新的請求。這能夠經過爲讀取地址薄的Ajax URL增長一個含有上次編輯時間的時間戳來實現,例如,&t=11900241612等。若是地址薄在上次下載後沒有被編輯過,時間戳就不變,則從瀏覽器的緩存中加載從而減小了一次HTTP請求過程。若是用戶修改過地址薄,時間戳就會用來肯定新的URL和緩存響應並不匹配,瀏覽器就會重要請求更新地址薄。
即便你的Ajxa響應是動態生成的,哪怕它只適用於一個用戶,那麼它也應該被緩存起來。這樣作能夠使你的Web2.0應用程序更加快捷。
五、推遲加載內容
你能夠仔細看一下你的網頁,問問本身「哪些內容是頁面呈現時所必需首先加載的?哪些內容和結構能夠稍後再加載?
把整個過程按照onload事件分隔成兩部分,JavaScript是一個理想的選擇。例如,若是你有用於實現拖放和動畫的JavaScript,那麼它就以等待稍後加載,由於頁面上的拖放元素是在初始化呈現以後才發生的。其它的例如隱藏部分的內容(用戶操做以後才顯現的內容)和處於摺疊部分的圖像也能夠推遲加載
工具能夠節省你的工做量:YUI Image Loader能夠幫你推遲加載摺疊部分的圖片,YUI Get utility是包含JS和 CSS的便捷方法。好比你能夠打開Firebug的Net選項卡看一下Yahoo的首頁。
當性能目標和其它網站開發實踐一致時就會相得益彰。這種狀況下,經過程序提升網站性能的方法告訴咱們,在支持JavaScript的狀況下,能夠先去除用戶體驗,不過這要保證你的網站在沒有JavaScript也能夠正常運行。在肯定頁面運行正常後,再加載腳原本實現如拖放和動畫等更加花哨的效果。
六、預加載
預加載和後加載看起來彷佛偏偏相反,但實際上預加載是爲了實現另一種目標。預加載是在瀏覽器空閒時請求未來可能會用到的頁面內容(如圖像、樣式表和腳本)。使用這種方法,當用戶要訪問下一個頁面時,頁面中的內容大部分已經加載到緩存中了,所以能夠大大改善訪問速度。
下面提供了幾種預加載方法:
無條件加載:觸發onload事件時,直接加載額外的頁面內容。以Google.com爲例,你能夠看一下它的spirit image圖像是怎樣在onload中加載的。這個spirit image圖像在google.com主頁中是不須要的,可是卻能夠在搜索結果頁面中用到它。
有條件加載:根據用戶的操做來有根據地判斷用戶下面可能去往的頁面並相應的預加載頁面內容。在search.yahoo.com中你能夠看到如何在你輸入內容時加載額外的頁面內容。
有預期的加載:載入從新設計過的頁面時使用預加載。這種狀況常常出如今頁面通過從新設計後用戶抱怨「新的頁面看起來很酷,可是卻比之前慢」。問題可能出在用戶對於你的舊站點創建了完整的緩存,而對於新站點卻沒有任何緩存內容。所以你能夠在訪問新站以前就加載一部內容來避免這種結果的出現。在你的舊站中利用瀏覽器的空餘時間加載新站中用到的圖像的和腳原本提升訪問速度。
七、減小DOM元素數量
一個複雜的頁面意味着須要下載更多數據,同時也意味着JavaScript遍歷DOM的效率越慢。好比當你增長一個事件句柄時在500和5000個DOM元素中循環效果確定是不同的。
大量的DOM元素的存在乎味着頁面中有能夠不用移除內容只須要替換元素標籤就能夠精簡的部分。你在頁面佈局中使用表格了嗎?你有沒有僅僅爲了佈局而引入更多的
元素呢?也許會存在一個適合或者在語意是更貼切的標籤能夠供你使用。
YUI CSS utilities能夠給你的佈局帶來巨大幫助:grids.css能夠幫你實現總體佈局,font.css和reset.css能夠幫助你移除瀏覽器默認格式。它提供了一個從新審視你頁面中標籤的機會,好比只有在語意上有意義時才使用
,而不是由於它具備換行效果才使用它。
DOM元素數量很容易計算出來,只須要在Firebug的控制檯內輸入:
document.getElementsByTagName('*').length
那麼多少個DOM元素算是多呢?這能夠對照有很好標記使用的相似頁面。好比Yahoo!主頁是一個內容很是多的頁面,可是它只使用了700個元素(HTML標籤)。
八、根據域名劃分頁面內容
把頁面內容劃分紅若干部分能夠使你最大限度地實現平行下載。因爲DNS查找帶來的影響你首先要確保你使用的域名數量在2個到4個之間。例如,你能夠把用到的HTML內容和動態內容放在www.example.org上,而把頁面各類組件(圖片、腳本、CSS)分別存放在statics1.example.org和statics.example.org上。
你可在Tenni Theurer和Patty Chi合寫的文章Maximizing Parallel Downloads in the Carpool Lane找到更多相關信息。
九、使iframe的數量最小
ifrmae元素能夠在父文檔中插入一個新的HTML文檔。瞭解iframe的工做理而後才能更加有效地使用它,這一點很重要。