优主张 2017-12-15
在上一篇,介绍一下渐进式 Web App(离线) - Part 1的文章中,我们讨论了典型的pwa应该是什么样子的并且同时也介绍了 server worker。到目前为止,我们已经缓存了应用壳。在 index.html和latet.html页面中,我们的应用已经实现了离线加载缓存数据。在重复访问时,它们的加载速度更快。在本教程第一部分的结尾,我们能够离线加载latest.html,但在用户离线时无法显示获得动态数据。这次学习我们将:
latest页面缓存 app的数据localStorage去存储 app 的数据在构建PWA时,需要考虑各种存储机制:
![[译]介绍一下渐进式 Web App(即时加载) - Part 2 [译]介绍一下渐进式 Web App(即时加载) - Part 2](https://cdn.ancii.com/article/image/v1/oc/VF/Tc/cTVcFouy1ynB2PexY2H0bfY8r-cCQDmQMfEQSZGEO_6tFoaEvTo4fKeLm_CRWH1g2F_cQdfg09LSe1VZrNxEQaXtr31f3Yl5vDZdTs2uDhcPoxAdz-rglwelhq9y0_BJz9rkGIwgXt0TYrdY-fn-og.jpg)
indexDB在浏览器的兼容性
Cache API:这是存储URL地址资源的最佳选择。和Service worker配合是非常好滴。
PouchDB:是CouchDB的开源JavaScript数据库。它使应用程序能够在本地存储数据,离线,然后同步与CouchDB和兼容的服务器应用程序时重新上线,保持用户数据同步,不管他们下一次在哪里登录。PouchDB支持所有现代浏览器,使用IndexedDB引擎失败的话就降级到WebSQL,对Firefox 29+ (包括 Firefox OS and Firefox for Android), Chrome 30+, Safari 5+, Internet Explorer 10+, Opera 21+, Android 4.0+, iOS 7.1+ 和 Windows Phone 8+等等都是兼容的。
Web Storage 例如 localStorage:它是同步的,是阻止DOM加载的,在浏览器中最多使用5MB, 它有简单的 api去操作存储键值对数据。
![[译]介绍一下渐进式 Web App(即时加载) - Part 2 [译]介绍一下渐进式 Web App(即时加载) - Part 2](https://cdn.ancii.com/article/image/v1/oc/VF/Tc/cTVcFouy1ynB2PexY2H0bfY8r-cCQDmQMfEQSZGEO_6KVv8GVroHjiVCMFpe0pZ6qAnpNp3L5Oz6AptrsuQkLaXtr31f3Yl5vDZdTs2uDhcPoxAdz-rglwelhq9y0_BJz9rkGIwgXt0TYrdY-fn-og.jpg)
Web Storage 的浏览器兼容表
根据PouchDB的维护者 Nolan Lawson说,在使用数据库时,最好问自己这些问题:
您可以查看考虑如何选择数据库,以便更全面地了解主题内容。
在我们的 web app 中,我们将用localStorage,由于我在本教程前面强调的局限性,我建议你不要在生产环境中使用localStorage。我们正在构建的应用程序非常简单,所以是使用了localStorage。
打开你的js/latest.js文件,我们更新fetchCommits方法去存储从Github API拉取的数据,存储在localStorage。代码如下:
function fetchCommits() {
var url = 'https://api.github.com/repos/unicodeveloper/resources-i-like/commits';
fetch(url)
.then(function(fetchResponse){
return fetchResponse.json();
})
.then(function(response) {
console.log("Response from Github", response);
var commitData = {};
for (var i = 0; i < posData.length; i++) {
commitData[posData[i]] = {
message: response[i].commit.message,
author: response[i].commit.author.name,
time: response[i].commit.author.date,
link: response[i].html_url
};
}
localStorage.setItem('commitData', JSON.stringify(commitData));
for (var i = 0; i < commitContainer.length; i++) {
container.querySelector("" + commitContainer[i]).innerHTML =
"<h4> Message: " + response[i].commit.message + "</h4>" +
"<h4> Author: " + response[i].commit.author.name + "</h4>" +
"<h4> Time committed: " + (new Date(response[i].commit.author.date)).toUTCString() + "</h4>" +
"<h4>" + "<a href='" + response[i].html_url + "'>Click me to see more!</a>" + "</h4>";
}
app.spinner.setAttribute('hidden', true); // hide spinner
})
.catch(function (error) {
console.error(error);
});
};上面有这段代码,在第一页加载的时候,这些提交的数据就存储到localStorage了,现在我们写另外一个函数去渲染这些localStorage的数据。代码如下:
// Get the commits Data from the Web Storage
function fetchCommitsFromLocalStorage(data) {
var localData = JSON.parse(data);
app.spinner.setAttribute('hidden', true); //hide spinner
for (var i = 0; i < commitContainer.length; i++) {
container.querySelector("" + commitContainer[i]).innerHTML =
"<h4> Message: " + localData[posData[i]].message + "</h4>" +
"<h4> Author: " + localData[posData[i]].author + "</h4>" +
"<h4> Time committed: " + (new Date(localData[posData[i]].time)).toUTCString() + "</h4>" +
"<h4>" + "<a href='" + localData[posData[i]].link + "'>Click me to see more!</a>" + "</h4>";
}
};这段代码将数据从本地存储并将其渲染 dom 节点。
现在我们需要知道,什么条件去调用fetchCommits函数和fetchCommitsFromLocalStorage函数。
js/latest.js代码如下
(function() {
'use strict';
var app = {
spinner: document.querySelector('.loader')
};
var container = document.querySelector('.container');
var commitContainer = ['.first', '.second', '.third', '.fourth', '.fifth'];
var posData = ['first', 'second', 'third', 'fourth', 'fifth'];
// Check that localStorage is both supported and available
function storageAvailable(type) {
try {
var storage = window[type],
x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
}
catch(e) {
return false;
}
}
// Get Commit Data from Github API
function fetchCommits() {
var url = 'https://api.github.com/repos/unicodeveloper/resources-i-like/commits';
fetch(url)
.then(function(fetchResponse){
return fetchResponse.json();
})
.then(function(response) {
console.log("Response from Github", response);
var commitData = {};
for (var i = 0; i < posData.length; i++) {
commitData[posData[i]] = {
message: response[i].commit.message,
author: response[i].commit.author.name,
time: response[i].commit.author.date,
link: response[i].html_url
};
}
localStorage.setItem('commitData', JSON.stringify(commitData));
for (var i = 0; i < commitContainer.length; i++) {
container.querySelector("" + commitContainer[i]).innerHTML =
"<h4> Message: " + response[i].commit.message + "</h4>" +
"<h4> Author: " + response[i].commit.author.name + "</h4>" +
"<h4> Time committed: " + (new Date(response[i].commit.author.date)).toUTCString() + "</h4>" +
"<h4>" + "<a href='" + response[i].html_url + "'>Click me to see more!</a>" + "</h4>";
}
app.spinner.setAttribute('hidden', true); // hide spinner
})
.catch(function (error) {
console.error(error);
});
};
// Get the commits Data from the Web Storage
function fetchCommitsFromLocalStorage(data) {
var localData = JSON.parse(data);
app.spinner.setAttribute('hidden', true); //hide spinner
for (var i = 0; i < commitContainer.length; i++) {
container.querySelector("" + commitContainer[i]).innerHTML =
"<h4> Message: " + localData[posData[i]].message + "</h4>" +
"<h4> Author: " + localData[posData[i]].author + "</h4>" +
"<h4> Time committed: " + (new Date(localData[posData[i]].time)).toUTCString() + "</h4>" +
"<h4>" + "<a href='" + localData[posData[i]].link + "'>Click me to see more!</a>" + "</h4>";
}
};
if (storageAvailable('localStorage')) {
if (localStorage.getItem('commitData') === null) {
/* The user is using the app for the first time, or the user has not
* saved any commit data, so show the user some fake data.
*/
fetchCommits();
console.log("Fetch from API");
} else {
fetchCommitsFromLocalStorage(localStorage.getItem('commitData'));
console.log("Fetch from Local Storage");
}
}
else {
toast("We can't cache your app data yet..");
}
})();在上面的代码片断,我们正在检查浏览器是否支持本地存储,如果它支持,我们继续检查是否已经缓存了提交数据。如果没有被缓存,我们将请求数据,显示到页面上并且缓存请求的数据。
现在,从新刷新一遍浏览器,确保你做了一个清晰的缓存,强制刷新,否则我们不会看到我们的代码更改的结果。
现在,离线并加载最新页面。将发生了什么事呢?
Yaaay!!! 它加载数据没有任何问题。
![[译]介绍一下渐进式 Web App(即时加载) - Part 2 [译]介绍一下渐进式 Web App(即时加载) - Part 2](https://cdn.ancii.com/article/image/v1/oc/VF/Tc/cTVcFouy1ynB2PexY2H0bfY8r-cCQDmQMfEQSZGEO_4TBo_bpbM8rVMgHNuQQ9iRFHhn1AhKHjF5e91CF5gMvKXtr31f3Yl5vDZdTs2uDhcPoxAdz-rglwelhq9y0_BJz9rkGIwgXt0TYrdY-fn-og.jpg)
查看DevTools,你间看到数据已经被缓存到localStorage
![[译]介绍一下渐进式 Web App(即时加载) - Part 2 [译]介绍一下渐进式 Web App(即时加载) - Part 2](https://cdn.ancii.com/article/image/v1/oc/VF/Tc/cTVcFouy1ynB2PexY2H0bfY8r-cCQDmQMfEQSZGEO_5sytLIpsSZ8FIoKwzC5B_TdfgaoCpl5xHutpj_61CkJqXtr31f3Yl5vDZdTs2uDhcPoxAdz-rglwelhq9y0_BJz9rkGIwgXt0TYrdY-fn-og.jpg)
当用户离线时,看看它加载的速度!!!
![[译]介绍一下渐进式 Web App(即时加载) - Part 2 [译]介绍一下渐进式 Web App(即时加载) - Part 2](https://cdn.ancii.com/article/image/v1/oc/VF/Tc/cTVcFouy1ynB2PexY2H0bfY8r-cCQDmQMfEQSZGEO_5tm4rS73wjptpGZQyirDRmHaATYMxhHVQD6cSDNDfeNKXtr31f3Yl5vDZdTs2uDhcPoxAdz-rglwelhq9y0_BJz9rkGIwgXt0TYrdY-fn-og.jpg)
现在,我们可以立即从本地存储获取数据。但是我们如何获得最新的数据?当用户在线时,我们需要一种仍然获得新数据的方法。
so easy, 让我们添加一个刷新按钮,触发一个请求到GitHub获得的最新数据。
打开latest.html文件,并且添加一个刷新按钮到<header>标签
<button id="butRefresh" class="headerButton" aria-label="Refresh"></button>
添加的按钮后<header>标签应该是这样的:
<header>
<svg class="menu__icon no--select" width="24px" height="24px" viewBox="0 0 48 48" fill="#fff">
<path d="M6 36h36v-4H6v4zm0-10h36v-4H6v4zm0-14v4h36v-4H6z"></path>
</svg>
PWA - Commits
<button id="butRefresh" class="headerButton" aria-label="Refresh"></button>
</header>最后,让我们在按钮上附加一个单击事件并添加功能。打开js/latest.js并且添加如下代码:
document.getElementById('butRefresh').addEventListener('click', function() {
// Get fresh, updated data from GitHub whenever you are clicked
toast('Fetching latest data...');
fetchCommits();
console.log("Getting fresh data!!!");
});清除缓存并重新加载。现在,你的latest.html页面看起来应该像这样:
![[译]介绍一下渐进式 Web App(即时加载) - Part 2 [译]介绍一下渐进式 Web App(即时加载) - Part 2](https://cdn.ancii.com/article/image/v1/oc/VF/Tc/cTVcFouy1ynB2PexY2H0bfY8r-cCQDmQMfEQSZGEO_5W5OegyhmB9KC7ZV13QvzkxS85Tuf3wtAgOOL9TYoehqXtr31f3Yl5vDZdTs2uDhcPoxAdz-rglwelhq9y0_BJz9rkGIwgXt0TYrdY-fn-og.jpg)
每当用户需要最新数据时,他们只需单击刷新按钮即可。
附加:
点击查看下面链接
上一篇: [译]介绍一下渐进式 Web App(离线) - Part 1
原文地址
项目代码地址
个人博客地址
如果有那个地方翻译出错或者失误,请各位大神不吝赐教,小弟感激不尽
期待下一篇: 介绍一下渐进式 Web App(消息推送) - Part 3