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

資訊專欄INFORMATION COLUMN

構(gòu)建離線web應(yīng)用(二)

curlyCheng / 971人閱讀

摘要:提及緩存時(shí),不僅僅是指存儲(chǔ),還包括瀏覽器內(nèi)用來(lái)保存數(shù)據(jù)以供離線使用的策略。當(dāng)請(qǐng)求成功返回時(shí),利用返回的數(shù)據(jù)更新頁(yè)面并緩存返回的數(shù)據(jù)。這種方案主要應(yīng)用用戶頻繁手動(dòng)更新內(nèi)容的場(chǎng)景,比如用戶的收件箱或者文章內(nèi)容。我們打算應(yīng)用的策略。

上一篇文章中,我們成功嘗試使用 service workers。我們也可以在應(yīng)用中緩存一些資源。這篇文章我們準(zhǔn)備了解這些:service workers 以及緩存是如何一起配合給用戶一個(gè)完美的離線體驗(yàn)。

在前一個(gè)章節(jié)當(dāng)我們學(xué)習(xí)如何 debugger 的時(shí)候,我們了解到瀏覽器的緩存存儲(chǔ)。提及緩存時(shí),不僅僅是指存儲(chǔ),還包括瀏覽器內(nèi)用來(lái)保存數(shù)據(jù)以供離線使用的策略。

在這篇文章中,我們將要:

了解社區(qū)中常見的緩存策略

嘗試可用的緩存 api

做一個(gè)用來(lái)展示 Github trending project 的 demo

在 demo 中演示離線狀態(tài)下利用緩存所帶來(lái)的體驗(yàn)

緩存策略

軟件工程中的每一個(gè)理論都是對(duì)同一類問題解決方案的總結(jié),每一個(gè)都需要時(shí)間整理并被大眾接受,成為推薦的解決方案。對(duì)于 PWA 的緩存策略來(lái)說同樣如此。Jake Archibald 匯總了很多常用的方案,但我們只打算介紹其中一些常用的:

Install 期間緩存

這個(gè)方案我們?cè)谏弦黄恼轮薪榻B過,緩存 app shell 展示時(shí)需要的所有資源:

self.addEventListener("install", function(e) {
  console.log("[ServiceWorker] Install");
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      console.log("[ServiceWorker] Caching app shell");
      return cache.addAll(filesToCache);
    })
  );
});

緩存的資源包括 HTML 模板,CSS 文件,JavaScript,fonts,少量的圖片。

緩存請(qǐng)求返回的數(shù)據(jù)

這個(gè)方案是指如果之前的網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)被緩存了,那么就用緩存的數(shù)據(jù)更新頁(yè)面。如果緩存不可用,那直接去網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)。當(dāng)請(qǐng)求成功返回時(shí),利用返回的數(shù)據(jù)更新頁(yè)面并緩存返回的數(shù)據(jù)。

self.addEventListener("fetch", function(event) {
  event.respondWith(
    caches.open(cacheName).then(function(cache) {
      return cache.match(event.request).then(function (response) {
        return response || fetch(event.request).then(function(response) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});

這種方案主要應(yīng)用用戶頻繁手動(dòng)更新內(nèi)容的場(chǎng)景,比如用戶的收件箱或者文章內(nèi)容。

先展示緩存,再根據(jù)請(qǐng)求的數(shù)據(jù)更新頁(yè)面

這種方案將同時(shí)請(qǐng)求緩存以及服務(wù)端的數(shù)據(jù)。如果某一項(xiàng)在緩存中有對(duì)應(yīng)的數(shù)據(jù),好,直接在頁(yè)面中展示。當(dāng)網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù)返回時(shí),利用返回的數(shù)據(jù)更新頁(yè)面:

let networkReturned = false;
if ("caches" in window) {
  caches.match(app.apiURL).then(function(response) {
    if (response) {
      response.json().then(function(trends) {
        console.log("From cache...")
        if(!networkReturned) {
          app.updateTrends(trends);
        }
      });
    }
  });
}

fetch(app.apiURL)
.then(response => response.json())
.then(function(trends) {
  console.log("From server...")
  networkReturned = true;
  app.updateTrends(trends.items)
}).catch(function(err) {
  // Error
});

在大多數(shù)情況下,網(wǎng)絡(luò)請(qǐng)求返回的數(shù)據(jù)會(huì)將從緩存中取出的數(shù)據(jù)覆蓋。但在網(wǎng)頁(yè)中,什么情況都有可能發(fā)生,有時(shí)候網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)比從緩存中取數(shù)據(jù)要快。因此,我們需要設(shè)置一個(gè) flag 來(lái)判斷網(wǎng)絡(luò)請(qǐng)求有沒有返回,這就是上例中的 networkReturned。

緩存部分技術(shù)選型

目前有兩種可持續(xù)性數(shù)據(jù)存儲(chǔ)方案 -- Cache Storage 以及 Index DB(IDB)。

Cache Storage:在過去的一段時(shí)間里,我們依賴 AppCache 來(lái)進(jìn)行緩存處理,但我們需要一個(gè)可操作性更強(qiáng)的 API。幸運(yùn)的是,瀏覽器提供了 Cache 這樣的一個(gè) API,給 Service Worker 的緩存操作帶來(lái)了更多的可能。并且,這個(gè) API 同時(shí)支持 service workers 以及 web 頁(yè)面。在前一篇文章中,我們已經(jīng)使用過了這個(gè) API。

Index DB:Index DB 是一個(gè)異步數(shù)據(jù)存儲(chǔ)方案。對(duì)于這個(gè) API 是又愛又恨,還好,像localForage這樣的類庫(kù)使用類似localStorage的操作方式簡(jiǎn)化了API。

Service Worker 對(duì)于這兩種存儲(chǔ)方案都提供支持。那么問題來(lái)了,什么場(chǎng)景下選擇哪一種技術(shù)方案呢? Addy Osmani 的博客已經(jīng)總結(jié)好了。

對(duì)于利用 URL 可直接查看的資源,使用支持 Service Worker 的 Cache Storage。其它類型的資源,使用利用 Promise 包裹之后的 IndexedDB。
SW Precache

上文已經(jīng)介紹了緩存策略以及數(shù)據(jù)緩存數(shù)據(jù)。在實(shí)戰(zhàn)之前,還想給大家介紹一下谷歌的 SW Precache。

這個(gè)工具還有一個(gè)額外的功能:將我們之前討論的緩存文件設(shè)置利用正則簡(jiǎn)化成一個(gè)配置對(duì)象。所有你需要做的就是在一個(gè)數(shù)組中定義緩存的項(xiàng)目。

讓我們來(lái)嘗試使用一下 precache,讓其自動(dòng)生成 service-worker.js。首先,我們需要在項(xiàng)目的根目錄下新增一個(gè) package.json 文件:

npm init -y

安裝 sw-precache:

npm install --save-dev sw-precache

創(chuàng)建一個(gè)配置文件:

// ./tools/precache.js

const name = "scotchPWA-v1"
module.exports = {
  staticFileGlobs: [
    "./index.html",
    "./images/*.{png,svg,gif,jpg}",
    "./fonts/**/*.{woff,woff2}",
    "./js/*.js",
    "./css/*.css",
    "https://fonts.googleapis.com/icon?family=Material+Icons"
  ],
  stripPrefix: "."
};

staticFileGlobs 里面利用正則匹配我們想要緩存的文件。只需要利用正則,比之前枚舉所有的文件簡(jiǎn)單很多。

package.json 中新增一個(gè) script 用來(lái)生成 service worker 文件:

"scripts": {
  "sw": "sw-precache --config=tools/precache.js --verbose"
},

運(yùn)行下面的命令即可生成 service worker 文件:

npm run sw

查看生成的文件,是不是很熟悉?

完成 demo

在做 web 應(yīng)用離線功能之前,讓我們先來(lái)完成應(yīng)用的基本功能。

回到 app.js 文件,我們要在頁(yè)面加載完成時(shí)去獲取當(dāng)前 Github 流行的項(xiàng)目(項(xiàng)目以 star 數(shù)的多少來(lái)排序):

(function() {
  const app = {
    apiURL: `https://api.github.com/search/repositories?q=created:%22${dates.startDate()}+..+${dates.endDate()}%22%20language:javascript&sort=stars&order=desc`
  }

  app.getTrends = function() {
    fetch(app.apiURL)
    .then(response => response.json())
    .then(function(trends) {
      console.log("From server...")
      app.updateTrends(trends.items)
    }).catch(function(err) {
      // Error
    });
  }

  document.addEventListener("DOMContentLoaded", function() {
    app.getTrends()
  })

  if ("serviceWorker" in navigator) {
    navigator.serviceWorker
     .register("/service-worker.js")
     .then(function() { 
        console.log("Service Worker Registered"); 
      });
  }
})()

注意 API URL 字符串中的日期。我們是這樣構(gòu)造的:

Date.prototype.yyyymmdd = function() {
  // getMonth is zero based,
  // so we increment by 1
  let mm = this.getMonth() + 1;
  let dd = this.getDate();

  return [this.getFullYear(),
          (mm>9 ? "" : "0") + mm,
          (dd>9 ? "" : "0") + dd
        ].join("-");
};

const dates = {
  startDate: function() {
     const startDate = new Date();
     startDate.setDate(startDate.getDate() - 7);
     return startDate.yyyymmdd();
   },
   endDate: function() {
     const endDate = new Date();
     return endDate.yyyymmdd();
   }
 }

yyyymmdd 幫我們將日期構(gòu)造成 Github API 所規(guī)定的格式(yyyy-mm-dd)。

當(dāng) getTrends 獲取數(shù)據(jù)之后,調(diào)用了 updateTrends 方法,傳入獲取到的數(shù)據(jù)。讓我們看看這個(gè)方法做了些什么:

app.updateTrends = function(trends) {
 const trendsRow = document.querySelector(".trends");
  for(let i = 0; i < trends.length; i++) {
    const trend = trends[i];
    trendsRow.appendChild(app.createCard(trend));
  }
}

遍歷請(qǐng)求返回的數(shù)據(jù),利用 createCard 來(lái)創(chuàng)建 DOM 模板,然后,將這段 DOM 插入 .trends 元素:



createCard 利用下面的代碼來(lái)創(chuàng)建模板:

const app = {
  apiURL: `...`,
  cardTemplate: document.querySelector(".card-template")
}

app.createCard = function(trend) {
  const card = app.cardTemplate.cloneNode(true);
  card.classList.remove("card-template")
  card.querySelector(".card-title").textContent = trend.full_name
  card.querySelector(".card-lang").textContent = trend.language
  card.querySelector(".card-stars").textContent = trend.stargazers_count
  card.querySelector(".card-forks").textContent = trend.forks
  card.querySelector(".card-link").setAttribute("href", trend.html_url)
  card.querySelector(".card-link").setAttribute("target", "_blank")
  return card;
}

下面就是所創(chuàng)建的 DOM 結(jié)構(gòu):


運(yùn)行時(shí)緩存的內(nèi)容

在應(yīng)用程序運(yùn)行時(shí),需要緩存從服務(wù)端獲取的動(dòng)態(tài)內(nèi)容。不再是 app shell 了,而是用戶真正瀏覽的內(nèi)容。

我們需要提前配置告訴 service worker ,在運(yùn)行時(shí)需要緩存的文件:

// ./tools/precache.js
const name = "scotchPWA-v1"
module.exports = {
  staticFileGlobs: [
    // ...
  ],
  stripPrefix: ".",
  // Run time cache
  runtimeCaching: [{
    urlPattern: /https://api.github.com/search/repositories/,
    handler: "networkFirst",
    options: {
      cache: {
        name: name
      }
    }
  }]
};

我們定義了一個(gè) url 正則匹配符,匹配成功時(shí),讀取緩存。這個(gè)正則匹配所有的 Github 搜索 API。我們打算應(yīng)用“Cache, Then network.”的策略。

這樣,我們先展示緩存的內(nèi)容,當(dāng)有網(wǎng)絡(luò)連接時(shí)候,更新內(nèi)容:

app.getTrends = function() {
 const networkReturned = false;
  if ("caches" in window) {
    caches.match(app.apiURL).then(function(response) {
      if (response) {
        response.json().then(function(trends) {
          console.log("From cache...")
          if(!networkReturned) {
            app.updateTrends(trends);
          }
        });
      }
    });
  }

  fetch(app.apiURL)
  .then(response => response.json())
  .then(function(trends) {
    console.log("From server...")
    app.updateTrends(trends.items)
    networkReturned = true;
  }).catch(function(err) {
    // Error
  });
}

precache.js 中更新緩存的版本,重新生成 service worker:

const name = "scotchPWA-v2"
npm run sw

當(dāng)你運(yùn)行應(yīng)用的時(shí)候,嘗試刷新,打開控制臺(tái),勾選 offline 選項(xiàng)。之后,刷新,以及見證奇跡的時(shí)刻:

刷新

用戶可能需要在網(wǎng)絡(luò)情況更佳的時(shí)候刷新頁(yè)面,我們需要給予用戶這樣的權(quán)利。我們可以給刷新按鈕添加一個(gè)事件,當(dāng)時(shí)間觸發(fā)時(shí),調(diào)用 getTrends 方法:

document.addEventListener("DOMContentLoaded", function() {
 app.getTrends()

 // Event listener for refresh button
 const refreshButton = document.querySelector(".refresh");
 refreshButton.addEventListener("click", app.getTrends)
})
下一步?

感覺不是很滿足?現(xiàn)在你已經(jīng)知道了如何創(chuàng)建離線應(yīng)用,在接下來(lái)的文章中,我們將繼續(xù)討論這項(xiàng)技術(shù)的有趣之處,包括推送通知,主屏幕圖標(biāo)創(chuàng)建等等···

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

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

相關(guān)文章

  • Web離線技術(shù)(一)—— 技術(shù)選型

    摘要:上面提到在安卓完全不需要像這樣大費(fèi)周章的繞彎路,所以安卓可能就不需要這個(gè)自定義的,這樣又會(huì)導(dǎo)致面臨著與安卓差異化嚴(yán)重問題。前言 最早接觸離線包的概念要追溯到16年初,項(xiàng)目迎來(lái)大改版,其中重點(diǎn)項(xiàng)目之一就是離線包方案的制定與實(shí)施。離線包顧名思義就是將H5/CSS/JS和資源文件打包提前下發(fā)到App中,這樣App在加載網(wǎng)頁(yè)的時(shí)候?qū)嶋H上加載的是本地的文件,減少網(wǎng)絡(luò)請(qǐng)求來(lái)提高網(wǎng)頁(yè)的渲染速度,并實(shí)現(xiàn)動(dòng)態(tài)...

    null1145 評(píng)論0 收藏0
  • 構(gòu)建離線WEB應(yīng)用

    摘要:使用離線應(yīng)用構(gòu)建應(yīng)用服務(wù)端服務(wù)器配置創(chuàng)建文件客戶端構(gòu)建,并在標(biāo)簽上添加屬性,屬性值是服務(wù)器上配置的緩存資源列表的文件名配置相關(guān)事件,創(chuàng)建離線文件內(nèi)容將狀態(tài)代碼轉(zhuǎn)化成狀態(tài)離線應(yīng)用創(chuàng)建即使沒有互聯(lián)網(wǎng)連接也可以使用的應(yīng)用程序。 HTML5新增了localstroage和application cache做離線緩存,兩種緩存各有應(yīng)用的場(chǎng)景,今天我們說說application cache這種方案...

    shleyZ 評(píng)論0 收藏0
  • 構(gòu)建離線WEB應(yīng)用

    摘要:使用離線應(yīng)用構(gòu)建應(yīng)用服務(wù)端服務(wù)器配置創(chuàng)建文件客戶端構(gòu)建,并在標(biāo)簽上添加屬性,屬性值是服務(wù)器上配置的緩存資源列表的文件名配置相關(guān)事件,創(chuàng)建離線文件內(nèi)容將狀態(tài)代碼轉(zhuǎn)化成狀態(tài)離線應(yīng)用創(chuàng)建即使沒有互聯(lián)網(wǎng)連接也可以使用的應(yīng)用程序。 HTML5新增了localstroage和application cache做離線緩存,兩種緩存各有應(yīng)用的場(chǎng)景,今天我們說說application cache這種方案...

    lk20150415 評(píng)論0 收藏0
  • 構(gòu)建離線web應(yīng)用(一)

    摘要:我喜歡移動(dòng),而且也是那些堅(jiān)持使用技術(shù)構(gòu)建移動(dòng)應(yīng)用程序的人之一。我們準(zhǔn)備做這樣的一個(gè)漸進(jìn)式應(yīng)用是典型的旨在提高用戶離線體驗(yàn)的應(yīng)用。當(dāng)我們開始構(gòu)建應(yīng)用時(shí),你就能理解上面的場(chǎng)景了。的作用范圍是針對(duì)相對(duì)路徑的。最佳的做法是在應(yīng)用的入口。 我喜歡移動(dòng)app,而且也是那些堅(jiān)持使用Web技術(shù)構(gòu)建移動(dòng)應(yīng)用程序的人之一。 經(jīng)過技術(shù)的不斷迭代(可能還有一些其它的東西),移動(dòng)體驗(yàn)設(shè)計(jì)愈來(lái)愈平易近人,給予用戶...

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

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

0條評(píng)論

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