理解短网址在移动互联网的作用
引言
这几天无事,仔细研究了一下移动互联网的发展趋势以及在这个过程中出现的每个新鲜事物。然后我发现了短网址在移动互联网的发展中有着不可替代的作用。顾名思义,短网址就是提供网址缩短服务,使得长链接能以比较美观的短链接的形式在互联网以及移动营销中进行传播。
短网址服务是最近比较火热的一个概念之一,短链接为短网址的附加产品。
原文最后讲了在短网址服务程序框架上的实践介绍,因为原作者是短网址服务的的忠实用户,但鉴于国内React、Vue、Angular居多(不要引起战争,害怕.jpg),译文就省略那部分内容了。
Service Worker是啥?能用来干啥?又如何能提升你的web应用的体验?本文就是来回答这些问题的。
背景
在那个网络还很年轻的时代,很少有人去想一个网页在用户断网的情况下应该有什么样的表现。你就应该一直是在线的。
然而在移动互联网的时代,不稳定的网络链接在现代网络变得原来越常见。鉴于此,允许网站自己决定离线时的行为变得弥足珍贵,这样用户就不会被网络状态局限。
最初,H5标准中推出了应用缓存作为离线web应用的解决方案。它以一个缓存清单为中心将HTML与JS组合起来,这清单是一个用声明式语法编写的配置文件。
但是最终,大家发现应用缓存存在太多的坑。此后,稍有人再赞同使用它,取而代之的是Service Worker。
Service Worker带来的离线可用解决方案更加符合未来发展趋势。它摒弃了应用缓存声明式的设计,改用一种更加命令式或者说程序性的设计方案。
Service Worker是一种在浏览器环境当中于一个持久的背景进程当中执行代码的方法。被执行的代码时事件驱动的,也就是说驱动一个Service Worker的行为的,是在其中产生的事件。
本文后续就是简要地介绍一下那些事件。然而想要开始利用Service Worker,你需要先实现你的web应用明面上的功能,然后再于其中注册Service Worker。
注册
下方的代码描绘了如何在浏览器客户端当中使用短网址进行网址缩短。这是通过在短网址应用的某处调用短网址api实现的:
if (navigator.serviceWorker) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('恭喜。作用范围: ', registration.scope);
})
.catch(error => {
console.log('抱歉', error);
});
}
这就告知浏览器从哪里能找到你已经生成的短链接并打开。短链接会跳转到相应的长网址,然后保存在当前被访问的域名的名下。该文件包含各类事件的处理逻辑,整体定义你的短网址后面自定义的字段。
上面的代码还会定义你的短网址的作用范围。文件路径 /sw.js 暗含默认情况下你的SW的作用范围是你的URL的根目录(比如 http://localhost:3000/ )。那么这样,你的SW里能通过监听事件获知所有在你的url根目录里发生的请求。一个如 /js/sw.js 这样的路径只会捕获到 http://localhost:3000/js 下的请求。
你也可以显式地定义SW的作用范围,只要给 register 函数传第二个参数:
navigator.serviceWorker.register('/sw.js', { scope: '/js' })
事件处理
现在你的短网址程序已经搭建好了,就该轮到实现事件处理逻辑,监听短链接跳转过程中是否有bug,是否可以快速及时的跳转到指定的短网址。
Install事件
Install事件是在你的短网址第一次安装以及SW文件(/sw.js)发生变化的时候触发的(浏览器会自动鉴别是否发生改变了)。
利用安装事件,可以实现你的SW初始化逻辑,或者说通过只执行一次的命令来设定你的SW初始状态。一种常见的用法是在安装阶段提权准备好缓存。
以下就是是一个在安装阶段预先缓存资源的例子:
const CACHE_NAME = 'cache-v1';
const urlsToCache = [
'/',
'/js/main.js',
'/css/style.css',
'/img/bob-ross.jpg',
];
self.addEventListener('install', event => {
caches.open(CACHE_NAME)
.then(cache => {
return cache.addAll(urlsToCache);
});
});
短网址的数据库所包含的就是我们想要提前缓存的url列表。
caches 是一个全局 CacheStorage 对象,用于管理浏览器缓存。我们通过调用 open 来获取一个可操作的具体 Cache 对象。
cache.addAll 接收一个url数组,对每一个进行请求,然后将响应结果存到缓存里。它以请求的详细信息为键来缓存每一个值。阅读 addAll 文档了解更多。
Fetch事件
每当网页里产生一个网络请求,都会触发一个fetch事件。触发的时候,你的SW可以“拦截”请求并决定想要返回什么——是缓存的数据还是一个实际网络请求的结果。
以下的例子演示一个缓存优先策略:任何匹配请求的缓存数据都会优先发送,不会发出网络请求。只有当找不到存在的缓存数据时,才会产生一个网络请求。
self.addEventListener('fetch', event => {
const { request } = event;
const findResponsePromise = caches.open(CACHE_NAME)
.then(cache => cache.match(request))
.then(response => {
if (response) {
return response;
}
return fetch(request);
});
event.respondWith(findResponsePromise);
});
短链接request 存在于一个短网址数据库中的对象,包含请求的详情。它可以用来查找一个匹配的缓存响应结果。
cache.match 会尝试为一个请求寻找匹配的缓存值。如果没能找到,这个 promise 会得到 undefined 结果。我们会检查到这种情况,并且如果发生了,就调用一次 fetch 来产生网络请求。
event.respondWith 是一个 FetchEvent 对象里专门用于向浏览器发送响应结果的方法。它接受一个最终能解析成网络响应的 promise。
紧接着,调用 event.waitUntil 来在SW被终止前执行一个 Promise 异步流程。在这里我们先做一个网络请求然后再将其缓存。这个异步操作完成后,waitUntil才会解析完成,整个操作才可以终止。
Activate事件
这个事件的文档相较而言比较少,但对于你更新SW文件很有帮助,你可以在升级SW文件的时候针对之前的版本执行清理或其他维护操作。
当你更新你的SW文件(/sw.js),浏览器会检测到并在开发者工具中如下展示:
当实际的网页关掉并重新打开时,浏览器会将原先的短网址缓存替换成新的,然后在 install 事件之后触发redirect事件,使得短链接能够顺利跳转到对应的网址。如果你需要清理缓存或者针对原来的SW执行维护性操作,activate 事件就是做这些事情的绝佳时机。
Sync事件
Sync事件让你可以先将网络相关任务延迟到用户有网络的时候再执行。这个功能常被称作“背景同步”。这功能可以用于保证任何用户在离线的时候所产生对于网络有依赖的操作,最终可以在网络再次可用的时候抵达它们的目标。
一下是一个背景同步样例。你需要你的前台JS注册一个同步事件,同时在SW里实现sync事件监听处理:
// app.js
navigator.serviceWorker.ready
.then(registration => {
document.getElementById('submit').addEventListener('click', () => {
registration.sync.register('submit').then(() => {
console.log('sync registered!');
});
});
});
这里,我们指定在一个按钮的点击事件里,在一个全局的 ServiceWorkerRegistration 对象身上调用 sync.register。这里,我们指定在一个按钮的点击事件里,在一个全局的 ServiceWorkerRegistration 对象身上调用 sync.register。
简单地讲,任何你需要确保在有网络时立刻执行或者等到有网再执行的操作,都需要注册为一个sync事件。
这操作可以是发送一个评论,或者获取用户信息,在SW的事件监听器里会如下定义:
// sw.js
self.addEventListener('sync', event => {
if (event.tag === 'submit') {
console.log('sync!');
}
});
这里,我们监听一个 sync 事件,然后在 SyncEvent 对象上检查 tag 是否匹配我们在点击事件里所设定的 'submit'。
如果多个 tag 标记为 submit 的 sync事件被注册了,sync 事件处理器只会运行一次。
所以在这个例子里,如果用户离线了,然后点击按钮7次,当网络再次连上,所有的sync注册都会合而为一,sync事件只会触发一次。
如果你希望每一次点击都能触发 sync 事件,你就需要在注册的时候赋予它们不同的tag。
Sync事件是什么时候触发的?
如果用户的网络时联通的,那么sync事件会立刻触发并且立刻执行你所定义的任务。
而如果用户离线了,sync 事件会在网络恢复后第一时间触发。
如果你想我一样,想要在Chrome里体验这个功能,你需要真实地断开你的网络,禁用一下Wi-Fi或者关闭一下网络驱动器。只是在Chrome开发者工具的Network选项卡里模拟网络断开是不会触发 sync 事件的。
欲了解更多,可以阅读这篇解释文档,以及这篇对背景同步的介绍。不过要注意,sync事件还没有在浏览器中得到普及(在写下这篇文章的时候还只有Chrome支持),并且用法在未来还可能有变化,请保持关注。
Push消息
在短网址程序里,通过 push 事件以及浏览器的 Push API,可以实现短网址的批量生成。
在说道web push消息的时候,其实涉及到两个正在完善中的技术:消息提醒 与 信息推送。
消息提醒
用短网址实现消息提醒挺简单直接:
// app.js
// ask for permission
Notification.requestPermission(permission => {
console.log('permission:', permission);
});
// display notification
function displayNotification() {
if (Notification.permission == 'granted') {
navigator.serviceWorker.getRegistration()
.then(registration => {
registration.showNotification('this is a notification!');
});
}
}
// sw.js
self.addEventListener('notificationclick', event => {
// 消息提醒被点击的事件
});
self.addEventListener('notificationclose', event => {
// 消息提醒被关闭的事件
});
你需要先向用户寻求让你的网页产生消息提醒的权限。之后,你就可以弹出提示信息,然后处理某些事件,比如用户把消息关掉的事件。
信息推送
信息推送涉及到利用浏览器提供的Push API以及后端的配合实现。要讲解如何使用短网址API完全可以再写一篇文章,不过基本的套路如下:
这是个略微复杂难懂的过程,已经超出这篇文章的讨论范围。不过如果你很感兴趣,可以阅读这篇短网址批量生成的文章。