成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

PJAX,站點(diǎn)加速之翼

WilsonLiu95 / 3439人閱讀

摘要:是一款可愛的小插件,將和瀏覽器的封裝到一起,解決了單純使用進(jìn)行無刷新加載時(shí)對(duì)搜索引擎的不友好,并且節(jié)省了開支提高了瀏覽速度,明顯地優(yōu)化了用戶體驗(yàn)。是提供的,是對(duì)瀏覽器歷史對(duì)象的增強(qiáng)。

pjax 是一款可愛的 jQuery 小插件,將 ajax 和瀏覽器的 pushState API 封裝到一起,解決了單純使用 ajax 進(jìn)行無刷新加載時(shí)對(duì)搜索引擎的不友好,并且節(jié)省了 HTTP 開支、提高了瀏覽速度,明顯地優(yōu)化了用戶體驗(yàn)。

知識(shí)要點(diǎn)

ajax 自不多說,在這里負(fù)責(zé)攜帶 pjax 標(biāo)識(shí)請(qǐng)求后端,將生成好的 html 碎片(注意不是前端取回JSON來進(jìn)行渲染)取回,然后 jQuery 將它替換到 DOM 當(dāng)中。

pushState 是 html5 提供的API,是對(duì)瀏覽器歷史對(duì)象 history 的增強(qiáng)。了解 Javascript 的都知道 BOM (瀏覽器對(duì)象模型),而 window 則是 BOM 的具體實(shí)現(xiàn),history 則是window 的子對(duì)象,這個(gè) pushState 就屬于 window.history 的一個(gè)方法。簡(jiǎn)單明了。

接下來,我們進(jìn)一步了解一下 pushState 。

先看下面的一段代碼:

var stateObj = { foo: "bar" }

history.pushState(stateObj, "title", "bar.html")

首先聲明一個(gè)狀態(tài)對(duì)象,能夠儲(chǔ)存任何可序列化數(shù)據(jù),比如將 html 碎片存儲(chǔ)于此,但大小有限制(640k),可以使用 localStorage 等機(jī)制。當(dāng)然也可以不使用,它的取舍我們后面具體實(shí)施時(shí)會(huì)提到。

pushState 方法往瀏覽器歷史棧里插入一條歷史項(xiàng),執(zhí)行完成之后,瀏覽器會(huì)立即將歷史項(xiàng)中的 url(bar.html) 顯示在地址欄中,(url 接受的是相對(duì)地址,會(huì)自動(dòng)補(bǔ)上域名),但不會(huì)將其加載。而 "title" 在這里暫時(shí)沒有用處,瀏覽器不會(huì)用它來修改頁面標(biāo)題,可以填 null。

那什么時(shí)機(jī)調(diào)用此方法?監(jiān)聽你需要 pjax 效果的超鏈接的 click 事件,禁用默認(rèn)的跳轉(zhuǎn),然后 do that。但講到這里你可能會(huì)想到,如果用戶進(jìn)行瀏覽器的前進(jìn)和后退操作,還是會(huì)執(zhí)行跳轉(zhuǎn)加載,那該如何處理呢?

這就要用到 pjax 不可忽視的關(guān)鍵角色 -- popstate 事件。這個(gè)事件只在瀏覽器的前進(jìn)和后退操作時(shí)觸發(fā),所以通過監(jiān)聽它,如法炮制上述操作即可 。至此,我們每一次的瀏覽訪問都向搜索引擎伸出了友好的橄欖枝。

講到這里,我們大體了解了 pjax 的流程,就是監(jiān)聽所有需要 pjax 效果的超鏈接,使用 ajax 和后端達(dá)成協(xié)議取回 html 碎片并填充到 DOM 當(dāng)中,pushState 負(fù)責(zé)將瀏覽器地址欄修改成我們想要的 URL,并且往歷史棧中增加一個(gè)歷史項(xiàng),通過監(jiān)聽 popstate,讓瀏覽器的前進(jìn)和后退也 pjax 化。

最后,replaceState 這個(gè) history API 也有必要介紹一下。當(dāng)你需要將當(dāng)前激活的歷史項(xiàng)從歷史棧中徹底抹去并替換成另一個(gè),那用它就對(duì)了,使用方法和 pushState 完全一樣,最常見的使用場(chǎng)景是使用 pjax 刷新頁面。

具體實(shí)施

pjax 的安裝配置需要前后端配合進(jìn)行。前后端的輪子都有不少現(xiàn)成的,但前端的輪子做不到開箱即用,這是因?yàn)?pjax 的實(shí)現(xiàn)需要結(jié)合項(xiàng)目的具體代碼進(jìn)行實(shí)施,下面我會(huì)分別講解。

前端采用最流行的 defunkt/jquery-pjax。話不多說,文檔寫的都很詳細(xì)。這里主要根據(jù)源碼提幾點(diǎn)需要注意的地方:

綁定選擇器時(shí),推薦使用 data-pjax 屬性,這個(gè)屬性會(huì)自動(dòng)尋找標(biāo)簽及其子標(biāo)簽中的超鏈接,綁定 click.pjax (順便注意這里的事件命名空間,目的是為了主動(dòng) trigger 時(shí)能區(qū)別對(duì)待 click) 事件。

$(document).pjax("[data-pjax] a, a[data-pjax]", "#pjax-container")

jquery-pjax 做到了自動(dòng)向后兼容,不需要多帶帶做兼容性判斷,放心調(diào)用 pjax 方法即可。

如果你的后端程序響應(yīng)慢,pjax 會(huì)不耐煩的直接跳轉(zhuǎn),要么將后端程序或者網(wǎng)絡(luò)環(huán)境優(yōu)化,要么讓 pjax 稍微耐心一點(diǎn):

$.pjax.defaults.timeout = 1600 /*默認(rèn) 650 毫秒*/

之所以說 pjax 不是開箱即用,主要是因?yàn)樗?js 腳本的調(diào)用會(huì)在第二次執(zhí)行 pjax 方法時(shí)失效。我剛開始遇到這個(gè)問題時(shí),一頭霧水,折騰了許久而不得解,然后在 laravel china 發(fā)帖求助,很快站長(zhǎng)龍哥就站出來,耐心細(xì)致的解答了我的疑惑。仔細(xì)研究了源碼,我發(fā)現(xiàn)了其中兩個(gè)有趣的函數(shù):

var container = extractContainer("", xhr, options)

executeScriptTags(container.scripts)

字面意思是將取回的 html 碎片 進(jìn)行加工處理成一個(gè)容器對(duì)象,并處理其中的腳本標(biāo)簽,那為什么第一次之后的 pjax 就沒執(zhí)行我的腳本呢?我們繼續(xù)閱讀兩個(gè)函數(shù)體內(nèi)的關(guān)鍵代碼:

extractContainer :

// Gather all script[src] elements
obj.scripts = findAll(obj.contents, "script[src]").remove()
obj.contents = obj.contents.not(obj.scripts)

將 html 碎片中的所有帶 src 的腳本刪除并儲(chǔ)存在容器對(duì)象的 scripts 屬性中,將去除了 scripts 的 html 碎片內(nèi)容賦給 contents 屬性??吹竭@里,你可能會(huì)大概明白了 pjax 的用意。繼續(xù)看另一個(gè)函數(shù)體的內(nèi)容:

executeScriptTags :

if (!scripts) return

  var existingScripts = $("script[src]")

  scripts.each(function() {
    var src = this.src
    var matchedScripts = existingScripts.filter(function() {
      return this.src === src
    })
    if (matchedScripts.length) return

    var script = document.createElement("script")
    var type = $(this).attr("type")
    if (type) script.type = type
    script.src = $(this).attr("src")
    document.head.appendChild(script)
  })

獲取目前 DOM 中的所有帶 src 的腳本,然后和 html 碎片中的腳本逐個(gè)做比對(duì),如果碎片中有新的腳本就將其插入到 head 標(biāo)簽的最后。啊哈~ pjax 這么做是確保不會(huì)重復(fù)請(qǐng)求任何已經(jīng)下載過的腳本文件,節(jié)省 HTTP 開支。但這么做的弊端就是本段開頭說的那個(gè)問題,那如何解決呢?

靈活運(yùn)用 pjax 提供的事件。 要解決上述問題,我們可以監(jiān)聽 pjax:end 事件,當(dāng)然 pjax:success 和 pjax:complete 也行,區(qū)別不大 :

  $(document).on("pjax:end", function() {
        self.blogBootUp()
  })

當(dāng) pjax 生命周期結(jié)束,主動(dòng)調(diào)用一下腳本啟動(dòng)程序即可。這里,我將我所有的腳本啟動(dòng)程序都封裝到 blogBootUp 中了,具體的代碼請(qǐng)移步我的 Blog 項(xiàng)目。

使用了 pjax ,就相當(dāng)于我們阻斷了瀏覽器的常規(guī)瀏覽機(jī)制,使用相關(guān)接口去重寫瀏覽邏輯。對(duì)于瀏覽器的前進(jìn)和后退功能,我們監(jiān)聽了 popstate 事件去使用 pjax,但在常規(guī)的情況下,瀏覽器是有緩存的,所以我們能秒進(jìn)或秒退,但如果 pjax 不優(yōu)化這一塊,那前進(jìn)和后退也要去請(qǐng)求服務(wù)器的話會(huì)付出不少的代價(jià)。查看 pjax 源碼發(fā)現(xiàn),作者是做了緩存處理的,通過兩個(gè)關(guān)鍵函數(shù) cachePushcachePop 來模擬瀏覽器緩存,只不過是存在數(shù)組中(也就是內(nèi)存中),如果你想達(dá)到 真正的 webApp 的水準(zhǔn),我覺得還需要配合 localStorage 和 WebSocket 等類似的機(jī)制來穩(wěn)健的存儲(chǔ)數(shù)據(jù)和靈活的控制頁面的緩存時(shí)間,當(dāng)然這就比較復(fù)雜了,待以后再去實(shí)踐好了。

后端我選用了 JacobBennett/pjax。兼容 laravel 5.* ,采用了中間件的形式,所以使用起來很簡(jiǎn)單,直接將中間件引入到 app/Http/Kernel.php 中即可。讀了下源碼,發(fā)現(xiàn)無非是使用了一個(gè) DOM 爬蟲根據(jù)客戶端 header 傳遞的 pjax 標(biāo)識(shí)和 pjax 容器標(biāo)識(shí) (就是 selector),抓取 laravel 響應(yīng)對(duì)象內(nèi)容中的 title 和 容器內(nèi)容,然后連綴在一起復(fù)寫回去,返回給客戶端。

最后,再推薦使用一個(gè)加載效果動(dòng)畫的 javascript 插件,配合 pjax 使用毫無違和感。rstacruz/nprogress,文檔寫的很簡(jiǎn)潔明了,有專門針對(duì) pjax 的使用說明,用上之后,還是相當(dāng)酷炫的。

參考資料

在 Laravel 應(yīng)用中使用 pjax 進(jìn)行頁面加速

PJAX的實(shí)現(xiàn)與應(yīng)用

HTML5 Page Cache with pjax + Web Storage + Firebase

defunkt/jquery-pjax

JacobBennett/pjax

原文鏈接:https://macken.me/article/speed-up-your-website-with-pjax

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/91170.html

相關(guān)文章

  • PJAX站點(diǎn)加速之翼

    摘要:是一款可愛的小插件,將和瀏覽器的封裝到一起,解決了單純使用進(jìn)行無刷新加載時(shí)對(duì)搜索引擎的不友好,并且節(jié)省了開支提高了瀏覽速度,明顯地優(yōu)化了用戶體驗(yàn)。是提供的,是對(duì)瀏覽器歷史對(duì)象的增強(qiáng)。 showImg(https://segmentfault.com/img/remote/1460000007640529?w=1008&h=569); pjax 是一款可愛的 jQuery 小插件,將 a...

    QiuyueZhong 評(píng)論0 收藏0
  • 收集整理適用博客建站免費(fèi)開源Wordpress主題-簡(jiǎn)約好看的WP主題

    摘要:最重要的就是找一個(gè)適合自己的主題了。事實(shí)上,免費(fèi)主題也非常多,而且很多的免費(fèi)主題在功能上和界面美觀上已經(jīng)大大超過了付費(fèi)的主題。加上這些主題都是開源的,基本上可以在上找得到源碼,安全性是沒有問題,主題的作者也在不斷更新當(dāng)中。WordPress最重要的就是找一個(gè)適合自己的主題了。好一點(diǎn)的WordPress主題基本上都是要收費(fèi)的,而且價(jià)格還不便宜,這導(dǎo)致了不少的新手朋友們很為難。而有時(shí)我們僅僅根據(jù)...

    番茄西紅柿 評(píng)論0 收藏2637
  • pjax不再神秘,hash、state那點(diǎn)事

    摘要:初步理解如果最近打電話給武漢的小伙伴,他說信號(hào)不好,那么相信我,他肯定不是真的信號(hào)不好,也不是不想和你說話,而是他可能在冰箱里。。。 初步理解 如果最近打電話給武漢的小伙伴,他說信號(hào)不好,那么相信我,他肯定不是真的信號(hào)不好,也不是不想和你說話,而是他可能在冰箱里。。。武漢的天氣從來都是喜怒無常的,是吧,屌絲氣十足,今年也是絲毫看不出有任何逆襲的跡象和可能性,當(dāng)然咱也沒必要去操那個(gè)心;好...

    solocoder 評(píng)論0 收藏0
  • Laravel 開源項(xiàng)目 『 糖果盒子 - Web 開發(fā)者的書簽導(dǎo)航 』

    摘要:項(xiàng)目概述糖果盒子是采用開發(fā)的站點(diǎn)導(dǎo)航應(yīng)用,專注分享優(yōu)質(zhì)開發(fā)資源站點(diǎn),希望成為開發(fā)人員最喜愛的的書簽導(dǎo)航。線上地址糖果盒子開發(fā)者的書簽導(dǎo)航地址求環(huán)境要求部署安裝本項(xiàng)目代碼使用框架開發(fā),本地開發(fā)環(huán)境使用。 showImg(https://segmentfault.com/img/remote/1460000012018405?w=3346&h=1950);showImg(https://s...

    姘存按 評(píng)論0 收藏0
  • Laravel 開源項(xiàng)目 『 糖果盒子 - Web 開發(fā)者的書簽導(dǎo)航 』

    摘要:項(xiàng)目概述糖果盒子是采用開發(fā)的站點(diǎn)導(dǎo)航應(yīng)用,專注分享優(yōu)質(zhì)開發(fā)資源站點(diǎn),希望成為開發(fā)人員最喜愛的的書簽導(dǎo)航。線上地址糖果盒子開發(fā)者的書簽導(dǎo)航地址求環(huán)境要求部署安裝本項(xiàng)目代碼使用框架開發(fā),本地開發(fā)環(huán)境使用。 showImg(https://segmentfault.com/img/remote/1460000012018405?w=3346&h=1950);showImg(https://s...

    summerpxy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<