转载自:https://blog.csdn.net/mogoweb/article/details/79029651

在开始PWA这个话题之前,我们先来看看Internet现状。

截至2017年1月,全球有80.5亿台联网设备(超过目前全球人口的75亿)。 这其中55%(44.2亿)是智能手机设备。 移动设备上的Chrome浏览器每月有10亿用户使用,比上一年增长了150%

据估计,到2020年全球将有400 - 500亿台设备互联。 大部分用户将来自农村和其他发展中国家,这些国家的数据要么昂贵,要么高延迟,或两者兼而有之。

用户行为:

来源:comScore Mobile Metrix, U.S

那么问题来了,为什么用户更喜欢使用应用程序而不是网站。

原因在于,原生应用程序具有以下优点
* 可靠
* 启动快
* 可以脱机工作
* 推送通知将用户带回应用程序
* 可见的主屏幕图标

但是,移动web的访问率几乎是应用程序的三倍

来源:comScore Mobile Metrix, U.S

当问题回到用户参与度上,移动web相较本地应用程序存在巨大差距(主要是由于Native应用程序提供了更多的优势和更好的用户体验)

移动web的优势

  • 即时性 - 移动网站即时可用
  • 可查找能力 - 移动网站可以很容易找到
  • 可达性 - 每月平均用户访问100个网站
  • 兼容性 - 移动网站可跨设备兼容
  • 可链接 - 通过URL轻松共享应用程序,不需要复杂的安装。
  • SEO - 移动网站内容可以被搜索引擎索引
  • 低阻力 - 要使用移动网站,您只需要一个浏览器,而不像应用程序,其开始推行的阻力非常大(译注:用户需要下载安装程序,还要安装程序)

那么,即使用户参与度较低,原生应用也能击败移动互联网,这是什么原因?

根据谷歌的研究,移动网站的平均加载时间是19秒,而用户期望在3秒之内加载该网站。所以如果网站加载时间超过3秒,将会损失大约40%的用户。如果需要超过10秒,将损失100%的用户。

此外,点击主屏幕图标比输入网址更轻松。

移动网站无法进行推送通知。

解决方案?

渐进式Web App(PWA)

什么是PWA?

PWA结合了最好的Web应用和最好的原生应用的用户体验。

包括
* 渐进式 - 每个用户都可用而不管选择什么样的浏览器,因为它们是以渐进式增强为核心原则构建的。
* 自适应 - 适应任何形态:桌面,移动设备,平板电脑或尚未出现的形式。
* 不依赖网络连接 - Service Workers允许离线工作,或在低质量网络上工作。
* 类似于应用程序 - 使用应用程序风格的交互和导航,感觉像一个应用程序。
* 保持最新 - 得益于service Woker的更新进程,应用能始终保持最新状态。
* 安全 - 借助于HTTPS,防止窥探,并确保内容没有被篡改
* 可发现 - 受益于W3C清单和service Worker注册作用域,搜索引擎可找到它们,可以识别为“应用程序”。
* 用户粘性 - 通过推送通知等功能让用户重返应用。
* 可安装 - 允许用户在主屏幕上“保留”他们认为最有用的应用程序,而无需经过应用程序商店。
* 可链接 - 通过URL轻松共享,不需要复杂的安装。

基本架构

Service Worker

位于客户端(浏览器)和服务器之间的代理。

  • 注册Service worker
if ('serviceWorker' in navigator) {
// Chrome, Firefox, Opera and Edge (16) /*
* scope (optional) default to the page root where it has been registered
* */ navigator.serviceWorker.register('/sw.js', {scope: './'}).then(function(registration) {
console.log('Service worker registration succeeded:', registration);
}).catch(function(error) {
console.log('Service worker registration failed:', error);
});
} else {
// IE, Safari
console.log('Service workers are not supported.');
}

sw_register.js

  • 如果浏览器支持SW并且已注册,则SW文件将在ServiceWorkerGlobalScope中运行,这是一个独立的执行线程,不具有DOM访问权限,也不会干扰JS主线程。 Service worker生命周期事件包括。
    1. 安装 - 主要用来缓存静态资源(js,css,图片等)
    2. 激活 - 主要用于缓存管理
    3. 空闲
    4. 收发消息 - 处理后续页面加载的所有网络请求
    5. 终止 - 不使用时,节省内存

Service worker脚本

/*
Copyright 2014 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/ // This polyfill provides Cache.add(), Cache.addAll(), and CacheStorage.match(),
// which are not implemented in Chrome 40.
importScripts('js/dependencies/cache-polyfill.js'); // While overkill for this specific sample in which there is only one cache,
// this is one best practice that can be followed in general to keep track of
// multiple caches used by a given service worker, and keep them all versioned.
// It maps a shorthand identifier for a cache to a specific, versioned cache name. // Note that since global state is discarded in between service worker restarts, these
// variables will be reinitialized each time the service worker handles an event, and you
// should not attempt to change their values inside an event handler. (Treat them as constants.) // If at any point you want to force pages that use this service worker to start using a fresh
// cache, then increment the CACHE_VERSION value. It will kick off the service worker update
// flow and the old cache(s) will be purged as part of the activate event handler when the
// updated service worker is activated. var urlsToPrefetch = [
'/',
'/page',
'/styles/common.css',
'/js/dependencies/autolinker.js',
'/template.js',
'/images/icon.png',
'/images/icon.svg',
]; var version = '1.0.0' self.addEventListener("install", function(event) {
console.log('WORKER: install event in progress.');
event.waitUntil(
/* The caches built-in is a promise-based API that helps you cache responses,
as well as finding and deleting them.
*/
caches
/* You can open a cache by name, and this method returns a promise. We use
a versioned cache name here so that we can remove old cache entries in
one fell swoop later, when phasing out an older service worker.
*/
.open(version + 'fundamentals')
.then(function(cache) {
/* After the cache is opened, we can fill it with the offline fundamentals.
The method below will add all resources we've indicated to the cache,
after making HTTP requests for each of them.
*/
return cache.addAll(urlsToPrefetch);
})
.then(function() {
console.log('WORKER: install completed');
})
);
}); self.addEventListener("fetch", function(event) {
console.log('WORKER: fetch event in progress.'); /* We should only cache GET requests, and deal with the rest of method in the
client-side, by handling failed POST,PUT,PATCH,etc. requests.
*/
if (event.request.method !== 'GET') {
/* If we don't block the event as shown below, then the request will go to
the network as usual.
*/
console.log('WORKER: fetch event ignored.', event.request.method, event.request.url);
return;
}
/* Similar to event.waitUntil in that it blocks the fetch event on a promise.
Fulfillment result will be used as the response, and rejection will end in a
HTTP response indicating failure.
*/
event.respondWith(
caches
/* This method returns a promise that resolves to a cache entry matching
the request. Once the promise is settled, we can then provide a response
to the fetch request.
*/
.match(event.request)
.then(function(cached) {
/* Even if the response is in our cache, we go to the network as well.
This pattern is known for producing "eventually fresh" responses,
where we return cached responses immediately, and meanwhile pull
a network response and store that in the cache.
Read more:
https://ponyfoo.com/articles/progressive-networking-serviceworker
*/
var networked = fetch(event.request)
// We handle the network request with success and failure scenarios.
.then(fetchedFromNetwork, unableToResolve)
// We should catch errors on the fetchedFromNetwork handler as well.
.catch(unableToResolve); /* We return the cached response immediately if there is one, and fall
back to waiting on the network as usual.
*/
console.log('WORKER: fetch event', cached ? '(cached)' : '(network)', event.request.url);
return cached || networked; function fetchedFromNetwork(response) {
/* We copy the response before replying to the network request.
This is the response that will be stored on the ServiceWorker cache.
*/
var cacheCopy = response.clone(); console.log('WORKER: fetch response from network.', event.request.url); caches
// We open a cache to store the response for this request.
.open(version + 'pages')
.then(function add(cache) {
/* We store the response for this request. It'll later become
available to caches.match(event.request) calls, when looking
for cached responses.
*/
cache.put(event.request, cacheCopy);
})
.then(function() {
console.log('WORKER: fetch response stored in cache.', event.request.url);
}); // Return the response so that the promise is settled in fulfillment.
return response;
} /* When this method is called, it means we were unable to produce a response
from either the cache or the network. This is our opportunity to produce
a meaningful response even when all else fails. It's the last chance, so
you probably want to display a "Service Unavailable" view or a generic
error response.
*/
function unableToResolve () {
/* There's a couple of things we can do here.
- Test the Accept header and then return one of the `offlineFundamentals`
e.g: `return caches.match('/some/cached/image.png')`
- You should also consider the origin. It's easier to decide what
"unavailable" means for requests against your origins than for requests
against a third party, such as an ad provider
- Generate a Response programmaticaly, as shown below, and return that
*/ console.log('WORKER: fetch request failed in both cache and network.'); /* Here we're creating a response programmatically. The first parameter is the
response body, and the second one defines the options for the response.
*/
return new Response('<h1>Service Unavailable</h1>', {
status: 503,
statusText: 'Service Unavailable',
headers: new Headers({
'Content-Type': 'text/html'
})
});
}
})
);
}); self.addEventListener("activate", function(event) {
/* Just like with the install event, event.waitUntil blocks activate on a promise.
Activation will fail unless the promise is fulfilled.
*/
console.log('WORKER: activate event in progress.'); event.waitUntil(
caches
/* This method returns a promise which will resolve to an array of available
cache keys.
*/
.keys()
.then(function (keys) {
// We return a promise that settles when all outdated caches are deleted.
return Promise.all(
keys
.filter(function (key) {
// Filter by keys that don't start with the latest version prefix.
return !key.startsWith(version);
})
.map(function (key) {
/* Return a promise that's fulfilled
when each outdated cache is deleted.
*/
return caches.delete(key);
})
);
})
.then(function() {
console.log('WORKER: activate completed.');
})
);
});

serviceworker.js

接下来:

PWA与React.js


且听下回分解

什么是渐进式Web App(PWA)?为什么值得关注?的更多相关文章

  1. [译]介绍一下渐进式 Web App(即时加载) - Part 2

    在上一篇,介绍一下渐进式 Web App(离线) - Part 1的文章中,我们讨论了典型的pwa应该是什么样子的并且同时也介绍了 server worker.到目前为止,我们已经缓存了应用壳.在 i ...

  2. 试着给VuePress添加渐进式Web应用(PWA)支持,基于vuepress/plugin-pwa,点亮离线访问

    背景 有时候,我们也希望VuePress构建的文档中心能支持离线访问,这时候我们需要给他添加渐进式Web应用(PWA,Progressive Web App)的支持,根据官方文档指引,我们可以借助插件 ...

  3. 渐进式web应用 (PWA)

    PWA(渐进式 Web 应用)运用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web 应用程序. PWA的特点: Discoverable, 内容可以通过搜索引擎发现. Instal ...

  4. 天人合一物我相融,站点升级渐进式Web应用PWA(Progressive Web Apps)实践

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_216 PWA(Progressive web apps,渐进式 Web 应用)使用现代的 Web API 以及传统的渐进式增强策略 ...

  5. Blazor WebAssembly 渐进式 Web 应用程序 (PWA) 使用 LocalStorage 离线处理数据

    原文链接:https://www.cnblogs.com/densen2014/p/16133343.html Window.localStorage 只读的localStorage 属性允许你访问一 ...

  6. 使用 React.js 的渐进式 Web 应用程序:第 1 部分 - 介绍

      使用 React.js 的渐进式 Web 应用程序:第 1 部分 - 介绍 使用 React.js 的渐进式 Web 应用程序:第 1 部分 - 介绍 来自译者 markzhai:大家也知道最近 ...

  7. Google_PWA_ServiceWork_渐进式 Web 应用_给应用提供离线体验

    前言:今天结识了google PWA提供的一个对移动端Web应用提供离线体验的一个功能,感觉很有用.我这里不分享自己的写法和代码.官网文档说的很详细,直接粘过来大家看吧. 推荐官网地址:你的第一个渐进 ...

  8. (转)PWA(Progressive Web App)渐进式Web应用程序

    PWA 编辑 讨论 PWA(Progressive Web App)是一种理念,使用多种技术来增强web app的功能,可以让网站的体验变得更好,能够模拟一些原生功能,比如通知推送.在移动端利用标准化 ...

  9. 渐进式Web应用(PWA)入门教程(上)

    最近关于渐进式Web应用有好多讨论,有一些人还在质疑渐进式Web应用是否就是移动端未来. 但在这篇文章中我并不会将渐进式APP和原生的APP进行比较,但有一点是可以肯定的,这两种APP的目标都是使用户 ...

随机推荐

  1. linux ssh tunnel

    ssh -qTfnN -D 7070 ape@192.168.1.35

  2. Dubbo源码分析:Invoker

    背景 调用对象!在调用过程可以使用Filter接口方法.Inovoker调用过程采用了装饰者设计模式.Filter最后一个ExcpetionFilter对象,这个对象之后就调用服务方法.服务对象是配置 ...

  3. SpringSecurity 整合 JWT

    项目集成Spring Security(一) 在上一篇基础上继续集成 JWT ,实现用户身份验证. 前言 前后端分离项目中,如果直接把 API 接口对外开放,我们知道这样风险是很大的,所以在上一篇中我 ...

  4. [ARIA] Add aria-expanded to add semantic value and styling

    In this lesson, we will be going over the attribute aria-expanded. Instead of using a class like .op ...

  5. LeetCode 958. Check Completeness of a Binary Tree

    原题链接在这里:https://leetcode.com/problems/check-completeness-of-a-binary-tree/ 题目: Given a binary tree, ...

  6. 21-ESP8266 SDK开发基础入门篇--C# TCP客户端 , 控制LED亮灭

    https://www.cnblogs.com/yangfengwu/p/11192603.html 由于是台式机,,没有插无线网卡...所以呢我就用调试助手监控下数据 后期让WIFI连接路由器的时候 ...

  7. 1.typescirpt学习之路,*.d.ts和@types关系理解

    今天看了看ts,文档上很多没用讲,小编疑惑了很久一个问题! *.d.ts和@types啥关系,小编查阅了很多文档,才弄明白. 首先,@types是npm的一个分支,我们把npm包发上去,npm包就会托 ...

  8. Python入门(一)-打开世界之Hello World

    关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号  欢迎大家关注我的微信公众号:「醉翁猫咪」 今天我们来用Python向世界说声Hello World,人生 ...

  9. Kerberos(一) 安装

    1.服务器基本信息 操作系统:centos7 数量:2 主机名映射关系 IP hostname server 192.168.4.50 manager1 Kerberos server(kdc) 19 ...

  10. Linux+Tomcat环境下安装SSL证书

    1.将申请好的证书(4个文件)文件放入/home/tomcat/apache-tomcat-9.0.12/conf/cert文件夹下2.(或者)将申请好的证书(4个文件)文件放入/home/tomca ...