成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

關于網(wǎng)頁內(nèi)容加速黑科技的趣談

開發(fā)
數(shù)周前,在倫敦 Heathrow 機場等飛機的空閑中,我順便處理了一些工作上的事情。不經(jīng)意間發(fā)現(xiàn) Github 在性能方面的一些問題,頗為詫異。通過新 tab 打開的頁面,其加載速度竟然比直接點擊鏈接打開的頁面要快。

[[206259]]

數(shù)周前,在倫敦 Heathrow 機場等飛機的空閑中,我順便處理了一些工作上的事情。不經(jīng)意間發(fā)現(xiàn) Github 在性能方面的一些問題,頗為詫異。通過新 tab 打開的頁面,其加載速度竟然比直接點擊鏈接打開的頁面要快。

點擊鏈接的同時復制鏈接并在新的 tab 頁中打開。可以看到,盡管先點擊的是鏈接,但渲染更快的卻是新 tab 中打開的頁面。

有一說一

頁面加載的時候,瀏覽器會接收網(wǎng)絡數(shù)據(jù)流,并將其輸出(pipe)給 HTML 解析器,HTML 解析器再將數(shù)據(jù)輸出到文檔。這意味著,頁面是邊加載邊渲染的。對于一個 100k 的頁面來說,瀏覽器很可能在接收到 20k 數(shù)據(jù)的時候就開始渲染出一些可用內(nèi)容了。

這個偉大又古老的特性,常常被開發(fā)者們有意無意地忽略了。多數(shù)提高加載性能的建議都歸結于一點,即“展示你所拿到的東西” —— 別怕,千萬不要傻傻等待一切加載完成之后再去展示內(nèi)容。

GitHub 當然是關注性能的,所以他們使用服務端渲染。但在同一個 tab 下瀏覽頁面時,他們用 JavaScript 重新實現(xiàn)了導航(navigation)功能,類似下面這樣:

  1. // …一堆重新實現(xiàn)瀏覽器導航功能代碼… 
  2. const response = await fetch('page-data.inc'); 
  3. const html = await response.text(); 
  4. document.querySelector('.content').innerHTML = html; 
  5. // …加載更多重新實現(xiàn)導航功能的代碼…  

這違反了規(guī)則,因為在 page-data.inc 下載完成之前什么事情都沒干。而服務端渲染版完全不會這樣囤積內(nèi)容,其內(nèi)容是流式的,這樣就要快得多了。就 Github 的客戶端渲染來說,很多 JavaScript 代碼完全減慢了渲染過程。

這里我僅僅只是拿 Github 舉例子 —— 這種反模式在單頁應用中比比皆是。

在頁面之內(nèi)切換內(nèi)容可能確實有些好處,特別是存在大量腳本的情況下,無需重新執(zhí)行全部腳本即可更新內(nèi)容。但我們能否在不放棄流的情況下完成這樣的工作呢?我曾經(jīng)常說 JavaScript 沒有辦法對流進行解析,但其實還是有的……

<iframe> 和 document.write 大法

iframe 早已躋身圈內(nèi)最臭黑科技之列。但下面這個辦法就使用了 iframe 和 document.write(),這樣我們就能將內(nèi)容以流的形式添加到頁面中了。示例如下:

  1. // 創(chuàng)建 iframe: 
  2. const iframe = document.createElement('iframe'); 
  3.  
  4. // 添加到 document 中 (記得隱藏起來): 
  5. iframe.style.display = 'none'
  6. document.body.appendChild(iframe); 
  7.  
  8. // 等待 iframe 加載: 
  9. iframe.onload = () => { 
  10.   // 忽略其他 onload 操作: 
  11.   iframe.onload = null
  12.   // 添加一個虛擬標簽: 
  13.   iframe.contentDocument.write('<streaming-element>'); 
  14.   // 引用該元素: 
  15.   const streamingElement = iframe.contentDocument.querySelector('streaming-element'); 
  16.   // 將該元素從 iframe 中取出,并添加到文檔中: 
  17.   document.body.appendChild(streamingElement); 
  18.   // 寫入一些內(nèi)容 —— 這里應該是異步的: 
  19.   iframe.contentDocument.write('<p>Hello!</p>'); 
  20.   // 繼續(xù)寫入內(nèi)容,直到完成: 
  21.   iframe.contentDocument.write('</streaming-element>'); 
  22.   iframe.contentDocument.close(); 
  23. }; 
  24.  
  25. //  iframe 初始化 
  26. iframe.src = '' 

雖然 Hello! 是寫到 iframe 中的,但它卻出現(xiàn)在了父級的 document 中!這是因為解析器維護了一個 敞開元素棧(stack of open elements),新創(chuàng)建的元素會被壓入棧中。就算我們把 <streaming-element/> 元素移出到 iframe 外面也不影響,就是這么任性。

此外,這種技術處理起 HTML 來,要比 innerHTML 更接近標準的頁面加載解析器。尤其是腳本依然會被下載,并在父級文檔的上下文中執(zhí)行 —— 只是在 Firefox 中完全不會執(zhí)行,但我認為這是個 bug更新: 其實腳本根本不應該執(zhí)行(感謝 Simon Pieters 指出這一點),但 Edge、Safari、Chrome 都這么干。

接下來我們只需要從服務端獲取 HTML 數(shù)據(jù)流,每當一個部分的數(shù)據(jù)到達的時候,就調(diào)用 iframe.contentDocument.write()。流式傳輸和 fetch() 搭配起來會更好,但為了支持 Safari,我們還是使用 XHR 來 hack 一下吧。

我已經(jīng)寫好了一個 demo,可以拿來和 Github 進行對比。下面是在 3G 網(wǎng)絡下的測試結果:

 

點擊這里查看原始測試數(shù)據(jù)

使用 iframe 進行流式渲染,頁面加載速度提高了 1.5 s。頭像也提前半秒鐘加載完成 —— 流式渲染意味著瀏覽器可以更早發(fā)現(xiàn)它們,并與內(nèi)容一起并行下載。

上面的方法對 Github 來說還是有效的,因為它的服務器返回的是 HTML。如果你使用的是框架,由框架自己管理 DOM 的展示,那可能就麻煩一些了。這種情況下可以看看下面這個次優(yōu)選項:

換行符分隔的 JSON

許多網(wǎng)站使用 JSON 驅動動態(tài)內(nèi)容。何其不幸,JSON 并不是一種對流友好的格式。盡管也有流式 JSON 解析器,可用起來卻并不那么簡單。

所以與其傳輸下面這樣一大塊 JSON 數(shù)據(jù):

  1.   "Comments": [ 
  2.     {"author""Alex""body""…"}, 
  3.     {"author""Jake""body""…"
  4.   ] 
  5.  

還不如像下面這樣一行輸出一個 JSON 對象:

  1. {"author""Alex""body""…"
  2.  
  3. {"author""Jake""body""…" 

這種被稱為 “換行符分隔的 JSON” 是有標準的:ndjson。給上面的內(nèi)容寫一個解析器就要簡單多了。到了 2017 年,我們也許可以使用一系列組合變換流(composable transform streams)來描述(譯者注:本文寫作于 2016 年 12 月):

  1. // 在 2017 年的某個時候可能會是這樣: 
  2. const response = await fetch('comments.ndjson'); 
  3. const comments = response.body 
  4.   // 從字節(jié)到文本: 
  5.   .pipeThrough(new TextDecoder()) 
  6.   // 一直緩沖,直到遇到換行符: 
  7.   .pipeThrough(splitStream('\n')) 
  8.   // 將內(nèi)容塊解析為JSON: 
  9.   .pipeThrough(parseJSON()); 
  10.  
  11. for await (const comment of comments) { 
  12.   // 處理每條評論,并將其添加到頁面: 
  13.   // (不管你使用的是什么模板或虛擬 DOM) 
  14.   addCommentToPage(comment); 
  15.  

在上面的代碼中,splitStream 和 parseJSON 是 可復用變換流(reusable transform streams)。與此同時,為了實現(xiàn)***程度的兼容,我們可以使用 XHR 進行 hack。

我再次新建了一個對比的 demo,下面是 3G 網(wǎng)絡下的結果:

 

點擊這里查看原始測試數(shù)據(jù)

與常規(guī) JSON 相比,ND-JSON 提前 1.5s 將內(nèi)容渲染到頁面上,盡管速度不如 iframe 方法那么快。在創(chuàng)建元素之前,必須等待完整的 JSON 對象出現(xiàn)。如果你的 JSON 文件體量巨大,可能會陷入對流的企盼之中。

單頁應用?別著急

如前所述,Github 使用了大量的代碼,然而卻帶來這樣的性能問題。在客戶端重新實現(xiàn)導航功能是困難的,如果你需要改變頁面中的大塊內(nèi)容,這么做有可能并不值得。

可以拿我們的嘗試與簡單瀏覽器導航進行對比:

 

點擊這里查看原始測試數(shù)據(jù)

打開一個簡單的沒有使用 JavaScript 瀏覽器導航的服務端渲染頁面的速度差不多是一樣的。但除去評論列表,測試頁面實在太過簡單。如果在不同頁面之間存在有大量重復的復雜內(nèi)容(主要是指可怕的廣告腳本),結果可能因實際情況而有差異,但一定要記得進行測試!很可能你編寫了一大堆代碼,然而只能帶來少的可憐的提升,甚至還可能減慢速度。 

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2018-05-16 15:09:37

AMD機械硬盤

2017-10-20 08:06:46

微軟

2017-07-07 10:24:56

云計算

2018-07-23 06:38:40

AI芯片數(shù)據(jù)中心

2020-04-29 13:30:38

腳本Chrome黑科技

2016-07-14 16:40:56

黑科技

2015-01-22 10:17:05

微軟win10

2023-09-22 08:27:39

2016-11-14 11:08:06

戴爾服務器

2018-11-07 09:56:26

2023-12-10 14:19:31

JupyterPython編碼

2016-10-11 16:43:04

小米5s超聲波指紋識別

2020-07-10 10:34:22

人工智能無人機物聯(lián)網(wǎng)

2016-11-10 19:31:00

蘇寧雙11

2014-08-12 13:38:15

2021-07-07 13:47:38

OCR游戲運行圖像

2013-07-12 14:09:16

2020-10-20 10:35:45

Windows操作系統(tǒng)功能

2020-08-25 15:38:50

科技網(wǎng)站工具
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一区二区免费 | 69热视频在线观看 | 国产日产欧产精品精品推荐蛮挑 | 亚洲人在线 | 亚洲一区二区视频在线播放 | 日韩欧美在线视频播放 | 国产一级片久久久 | 精品日韩一区二区三区 | av毛片| 阿v视频在线观看 | 在线日韩欧美 | 3p视频在线观看 | 国产精品揄拍一区二区 | 欧美黄a | 亚洲日本国产 | 一区二区三区欧美大片 | 国产精品不卡视频 | 中文字幕精品一区久久久久 | 国产精品国产成人国产三级 | 国产精品视频一 | 国产欧美在线视频 | 精品欧美一区二区三区免费观看 | 黄色毛片在线看 | 国产精品美女久久久久久久网站 | 中文在线一区二区 | 国产欧美视频一区二区 | 国产欧美日韩精品在线观看 | h视频免费看 | 亚洲欧美日韩精品久久亚洲区 | 成人精品免费视频 | 国产黄色在线观看 | a久久| 日本大片在线播放 | 午夜精品网站 | 免费观看的av毛片的网站 | 桃色五月 | 日韩三片| 国产日韩av一区二区 | 欧美日韩精品一区二区三区四区 | 精品亚洲视频在线 | 亚洲精品中文字幕中文字幕 |