《offline coolbook》笔记
https://jakearchibald.com/2014/offline-cookbook/
在install中对依赖进行缓存
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('mysite-static-v3').then(function(cache) {
return cache.addAll([
'/css/whatever-v3.css',
'/css/imgs/sprites-v6.png',
'/css/fonts/whatever-v8.woff',
'/js/all-min-v4.js'
// etc
]);
})
);
});
waitUntil接收的参数是一个promise,这个promise决定了install阶段的持续时长和是否成功。
在install中对非依赖进行缓存
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('mygame-core-v1').then(function(cache) {
cache.addAll(
// levels 11-20
);
return cache.addAll(
// core assets & levels 1-10
);
})
);
});
以上waitUntil接收到的promise,仅仅是对应加载了核心的缓存。虽然也加载了非关键的缓存(levels11-20),但是对install的状态无影响。
在activate阶段清除缓存
self.addEventListener('activate', function(event) {
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.filter(function(cacheName) {
// Return true if you want to remove this cache,
// but remember that caches are shared across
// the whole origin
}).map(function(cacheName) {
return caches.delete(cacheName);
})
);
})
);
});
Keep your activation as lean as possible, only use it for things you couldn't do while the old version was active
处理用户的交互
给用户一个按钮,让用户选择保存某些资源以离线访问。资源的唯一标识与某个cache要一一对应
document.querySelector('.cache-article').addEventListener('click', function(event) {
event.preventDefault(); var id = this.dataset.articleId;
caches.open('mysite-article-' + id).then(function(cache) {
fetch('/get-article-urls?id=' + id).then(function(response) {
// /get-article-urls returns a JSON-encoded array of
// resource URLs that a given article depends on
return response.json();
}).then(function(urls) {
cache.addAll(urls);
});
});
});
以上代码与sw是否被激活无关。也就是说cache和sw的运行是分开的两部分。
拦截网络请求
当一个请求的响应不在cache中,就从网络获取,显示到界面上,最后保存到cache中。
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').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;
});
});
})
);
});
以上的clone是为了让页面对response的读取与cache对response的读取分离开来,互不影响。
更新cache
总是先更新缓存
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').then(function(cache) {
return cache.match(event.request).then(function(response) {
var fetchPromise = fetch(event.request).then(function(networkResponse) {
cache.put(event.request, networkResponse.clone());
return networkResponse;
})
return response || fetchPromise;
})
})
);
});
消息推送
后台同步
只使用缓存
self.addEventListener('fetch', function(event) {
// If a match isn't found in the cache, the response
// will look like a connection error
event.respondWith(caches.match(event.request));
});
只使用网络
self.addEventListener('fetch', function(event) {
event.respondWith(fetch(event.request));
// or simply don't call event.respondWith, which
// will result in default browser behaviour
});
缓存优先,后访问网络
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
})
访问缓存和访问网络同时开始
对于某些情况,古老的硬盘+病毒扫描软件+快速的网络。访问网络的速度可能比访问硬盘更快。
self.addEventListener('fetch', function(event) {
event.respondWith(
promiseAny([
caches.match(event.request),
fetch(event.request)
])
);
});
访问网络失败后才取缓存
self.addEventListener('fetch', function(event) {
event.respondWith(
fetch(event.request).catch(function() {
return caches.match(event.request);
})
);
});
用于资源经常更新的站点,当离线访问时才使用旧的资源。
访问缓存后再访问网络
var networkDataReceived = false; startSpinner(); // fetch fresh data
var networkUpdate = fetch('/data.json').then(function(response) {
return response.json();
}).then(function(data) {
networkDataReceived = true;
updatePage();
}); // fetch cached data
caches.match('/data.json').then(function(response) {
if (!response) throw Error("No data");
return response.json();
}).then(function(data) {
// don't overwrite newer network data
if (!networkDataReceived) {
updatePage(data);
}
}).catch(function() {
// we didn't get cached data, the network is our last hope:
return networkUpdate;
}).catch(showErrorMessage).then(stopSpinner);
generic fallback
self.addEventListener('fetch', function(event) {
event.respondWith(
// Try the cache
caches.match(event.request).then(function(response) {
// Fall back to network
return response || fetch(event.request);
}).catch(function() {
// If both fail, show a generic fallback:
return caches.match('/offline.html');
// However, in reality you'd have many different
// fallbacks, depending on URL & headers.
// Eg, a fallback silhouette image for avatars.
})
);
});
模板
importScripts('templating-engine.js'); self.addEventListener('fetch', function(event) {
var requestURL = new URL(event.request); event.respondWith(
Promise.all([
caches.match('/article-template.html').then(function(response) {
return response.text();
}),
caches.match(requestURL.path + '.json').then(function(response) {
return response.json();
})
]).then(function(responses) {
var template = responses[0];
var data = responses[1]; return new Response(renderTemplate(template, data), {
headers: {
'Content-Type': 'text/html'
}
});
})
);
});
大概意思就是app shell缓存在本地,然后请求动态数据,两者渲染,得出结果。
将以上的技巧组合到一起
self.addEventListener('fetch', function(event) {
// Parse the URL:
var requestURL = new URL(event.request.url); // Handle requests to a particular host specifically
if (requestURL.hostname == 'api.example.com') {
event.respondWith(/* some combination of patterns */);
return;
}
// Routing for local URLs
if (requestURL.origin == location.origin) {
// Handle article URLs
if (/^\/article\//.test(requestURL.pathname)) {
event.respondWith(/* some other combination of patterns */);
return;
}
if (/\.webp$/.test(requestURL.pathname)) {
event.respondWith(/* some other combination of patterns */);
return;
}
if (request.method == 'POST') {
event.respondWith(/* some other combination of patterns */);
return;
}
if (/cheese/.test(requestURL.pathname)) {
event.respondWith(
new Response("Flagrant cheese error", {
status: 512
})
);
return;
}
} // A sensible default pattern
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
完。
《offline coolbook》笔记的更多相关文章
- HTML+CSS笔记 CSS笔记集合
HTML+CSS笔记 表格,超链接,图片,表单 涉及内容:表格,超链接,图片,表单 HTML+CSS笔记 CSS入门 涉及内容:简介,优势,语法说明,代码注释,CSS样式位置,不同样式优先级,选择器, ...
- CSS笔记--选择器
CSS笔记--选择器 mate的使用 <meta charset="UTF-8"> <title>Document</title> <me ...
- HTML+CSS笔记 CSS中级 一些小技巧
水平居中 行内元素的水平居中 </a></li> <li><a href="#">2</a></li> &l ...
- HTML+CSS笔记 CSS中级 颜色&长度值
颜色值 在网页中的颜色设置是非常重要,有字体颜色(color).背景颜色(background-color).边框颜色(border)等,设置颜色的方法也有很多种: 1.英文命令颜色 语法: p{co ...
- HTML+CSS笔记 CSS中级 缩写入门
盒子模型代码简写 回忆盒模型时外边距(margin).内边距(padding)和边框(border)设置上下左右四个方向的边距是按照顺时针方向设置的:上右下左. 语法: margin:10px 15p ...
- HTML+CSS笔记 CSS进阶再续
CSS的布局模型 清楚了CSS 盒模型的基本概念. 盒模型类型, 我们就可以深入探讨网页布局的基本模型了.布局模型与盒模型一样都是 CSS 最基本. 最核心的概念. 但布局模型是建立在盒模型基础之上, ...
- HTML+CSS笔记 CSS进阶续集
元素分类 在CSS中,html中的标签元素大体被分为三种不同的类型:块状元素.内联元素(又叫行内元素)和内联块状元素. 常用的块状元素有: <div>.<p>.<h1&g ...
- HTML+CSS笔记 CSS进阶
文字排版 字体 我们可以使用css样式为网页中的文字设置字体.字号.颜色等样式属性. 语法: body{font-family:"宋体";} 这里注意不要设置不常用的字体,因为如果 ...
- HTML+CSS笔记 CSS入门续集
继承 CSS的某些样式是具有继承性的,那么什么是继承呢?继承是一种规则,它允许样式不仅应用于某个特定html标签元素,而且应用于其后代(标签). 语法: p{color:red;} <p> ...
- HTML+CSS笔记 CSS入门
简介: </span>年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的<span>脚本解释程序</span>,作为ABC语言的一种继承. & ...
随机推荐
- javascript 中not defined 和undefined有什么区别
概念上的解释:undefined是javascript语言中定义的五个原始类中的一个,换句话说,undefined并不是程序报错,而是程序允许的一个值.not defined是javascript在运 ...
- scrapy框架中Item Pipeline用法
scrapy框架中item pipeline用法 当Item 在Spider中被收集之后,就会被传递到Item Pipeline中进行处理 每个item pipeline组件是实现了简单的方法的pyt ...
- JS面向对象方法(一): 使用原生JS 实现导航栏下多级分类弹出效果
利用二级菜单的onmouseover/out事件 重新构建一级菜单 ".hover" 样式类 代码如下: CSS部分: 在原来的目标:hover样式中 增加 .hover状态 li ...
- 洛谷 P4174 [NOI2006]最大获利 && 洛谷 P2762 太空飞行计划问题 (最大权闭合子图 && 最小割输出任意一组方案)
https://www.luogu.org/problemnew/show/P4174 最大权闭合子图的模板 每个通讯站建一个点,点权为-Pi:每个用户建一个点,点权为Ci,分别向Ai和Bi对应的点连 ...
- Machine Learning Codeforces - 940F(带修莫队) && 洛谷P4074 [WC2013]糖果公园
以下内容未验证,有错请指正... 设块大小为T,则块数为$\frac{n}{T}$ 将询问分为$(\frac{n}{T})^2$块(按照左端点所在块和右端点所在块分块),同块内按时间从小到大依次处理 ...
- DTO和ViewModel的区别
Data Transfer Object 数据传输对象 ViewModel 视图实体(我们在新建MVC项目是会发现Model文件夹下会有一些ViewModel实体) 简单的理解一下两者之间的区别,举个 ...
- 20170308web作业1
代码20170308001: <%@ page language="java" import="java.util.*" pageEncoding=&qu ...
- org.apache.axis2.AxisFault: Service class XXXXX must have public as access Modifier解决方案
使用Axis2工具生成客户端调用辅助类后,编写客户端调用代码运行时报错,完整错误信息如下: log4j:WARN No appenders could be found for logger (org ...
- [windows]命令行关机或重启电脑
1.关机:菜单--〉运行--〉输入:cmd--〉输入:shutdown -s -t 0 2.重启:菜单--〉运行--〉输入:cmd--〉输入:shutdown -r -t 0 (注:“-r”代表重启, ...
- LR中操中MySQL脚本模板
Action(){ char chQuery[128]; MYSQL *Mconn; int result; //引入mysql动态链接库 lr_load_dll("libmysql.dll ...