classWarmRestart(lr_scheduler.CosineAnnealingLR): """This class implements Stochastic Gradient Descent with Warm Restarts(SGDR): https://arxiv.org/abs/1608.03983. Set the learning rate of each parameter group using a cosine annealing schedule, When last_epoch=-1, sets initial lr as lr. This can't support scheduler.step(epoch). please keep epoch=None. """
def__init__(self, optimizer, T_max=30, T_mult=1, eta_min=0, last_epoch=-1): """implements SGDR Parameters: ---------- T_max : int Maximum number of epochs. T_mult : int Multiplicative factor of T_max. eta_min : int Minimum learning rate. Default: 0. last_epoch : int The index of last epoch. Default: -1. """ self.T_mult = T_mult super().__init__(optimizer, T_max, eta_min, last_epoch)
Progressive Web App 是继 Ajax、响应式设计、HTML5 之后,web 平台的又一次革命性突破。它在开放 Web 标准的基础之上,突破了以往 Web 应用只能「依赖互联网分发」与「依赖浏览器为入口」的两大桎梏,一下子打开了 Web 应用从性能、架构到用户体验上的一系列可能性。
PWA 中最引入注目的核心新特性,Service Worker,实质上是为 Web 应用带来了一种安全而又低功耗的后台处理能力。无论是用于实现离线 Web 应用所需要的缓存读写与网络代理,还是用于提升 Web 应用能力的推送通知、后台同步,其实都得益于这种新的并发能力。随着 Edge 与 Safari 的相继发布,Service Worker 已经历史性的达到了全浏览器的支持。
而这就要归功于 Web 开放性的力量。相比于其他众多私有的“类 Web”技术,PWA 技术完全属于开放 Web 标准。PWA 因此具备了独一无二的跨平台能力,不止于移动端,Chrome 与 Windows 已经让 PWA 在桌面端也晋升为了第一公民。这使得「一套代码,发布可以同时跨移动桌面设备、跨操作系统、跨浏览器的超级应用」真正成为可能。这里有非常大的想象空间,非常值得我们期待。
近年来,Web 应用在整个软件与互联网行业承载的责任越来越重,软件复杂度和维护成本越来越高,Web 技术,尤其是 Web 客户端技术,迎来了爆发式的发展。
包括但不限于基于 Node.js 的前端工程化方案;诸如 Webpack、Rollup 这样的打包工具;Babel、PostCSS 这样的转译工具;TypeScript、Elm 这样转译至 JavaScript 的编程语言;React、Angular、Vue 这样面向现代 web 应用需求的前端框架及其生态,也涌现出了像同构 JavaScript与通用 JavaScript 应用这样将服务器端渲染(Server-side Rendering)与单页面应用模型(Single-page App)结合的 web 应用架构方式,可以说是百花齐放。
但是,Web 应用在移动时代并没有达到其在桌面设备上流行的程度。究其原因,尽管上述的各种方案已经充分利用了现有的 JavaScript 计算能力、CSS 布局能力、HTTP 缓存与浏览器 API 对当代基于 Ajax 与响应式设计的 web 应用模型的性能与体验带来了工程角度的巨大突破,我们仍然无法在不借助原生程序辅助浏览器的前提下突破 web 平台本身对 web 应用固有的桎梏:客户端软件(即网页)需要下载所带来的网络延迟;与 Web 应用依赖浏览器作为入口所带来的体验问题。
在桌面设备上,由于网络条件稳定,屏幕尺寸充分,交互方式趋向于多任务,这两点造成的负面影响对比 web 应用免于安装、随叫随到、无需更新等优点,瑕不掩瑜。但是在移动时代,脆弱的网络连接与全新的人机交互方式使得这两个问题被无限放大,严重制约了 web 应用在移动平台的发展。在用户眼里,原生应用不会出现「白屏」,清一色都摆在主屏幕上;而 web 应用则是浏览器这个应用中的应用,使用起来并不方便,而且加载也比原生应用要慢。
Progressive Web Apps(以下简称 PWA)以及构成 PWA 的一系列关键技术的出现,终于让我们看到了彻底解决这两个平台级别问题的曙光:能够显著提高应用加载速度、甚至让 web 应用可以在离线环境使用的 Service Worker 与 Cache Storage;用于描述 web 应用元数据(metadata)、让 web 应用能够像原生应用一样被添加到主屏、全屏执行的 Web App Manifest;以及进一步提高 web 应用与操作系统集成能力,让 web 应用能在未被激活时发起推送通知的 Push API 与 Notification API 等等。
当浏览器发现用户需要 Flipkart Lite 时,它就会提示用户「嘿,你可以把它添加至主屏哦」(用户也可以手动添加)。这样,Flipkart Lite 就会像原生应用一样在主屏上留下一个自定义的 icon 作为入口;与一般的书签不同,当用户点击 icon 时,Flipkat Lite 将直接全屏打开,不再受困于浏览器的 UI 中,而且有自己的启动屏效果。
<!-- Add to homescreen for Safari on iOS --> <metaname="apple-mobile-web-app-capable"content="yes"> <metaname="apple-mobile-web-app-status-bar-style"content="black"> <metaname="apple-mobile-web-app-title"content="Lighten">
<!-- Add to homescreen for Chrome on Android --> <metaname="mobile-web-app-capable"content="yes"> <matename="theme-color"content="#000000">
<!-- Icons for iOS and Android Chrome M31~M38 --> <linkrel="apple-touch-icon-precomposed"sizes="144x144"href="images/touch/apple-touch-icon-144x144-precomposed.png"> <linkrel="apple-touch-icon-precomposed"sizes="114x114"href="images/touch/apple-touch-icon-114x114-precomposed.png"> <linkrel="apple-touch-icon-precomposed"sizes="72x72"href="images/touch/apple-touch-icon-72x72-precomposed.png"> <linkrel="apple-touch-icon-precomposed"href="images/touch/apple-touch-icon-57x57-precomposed.png">
<!-- Icon for Android Chrome, recommended --> <linkrel="shortcut icon"sizes="196x196"href="images/touch/touch-icon-196x196.png">
我们原有的整个 Web 应用模型,都是构建在「用户能上网」的前提之下的,所以一离线就只能玩小恐龙了。其实,对于「让 web 应用离线执行」这件事,Service Worker 至少是 web 社区的第三次尝试了。
故事可以追溯到 2007 年的 Google Gears:为了让自家的 Gmail、Youtube、Google Reader 等 web 应用可以在本地存储数据与离线执行,Google 开发了一个浏览器拓展来增强 web 应用。Google Gears 支持 IE 6、Safari 3、Firefox 1.5 等浏览器;要知道,那一年 Chrome 都还没出生呢。
在 Gears API 中,我们通过向 LocalServer 模块提交一个缓存文件清单来实现离线支持:
1 2 3 4
// Somewhere in your javascript var localServer = google.gears.factory.create("bata.localserver"); var store = localServer.createManagedStore(STORE_NAME); store.manifestUrl = "manifest.json"
HTML5 App Cache 作为第二波「让 web 应用离线执行」的尝试,确实也服务了比如 Google Doc、尤雨溪早年作品 HTML5 Clear、以及一直用 web 应用作为自己 iOS 应用的 FT.com(Financial Times)等不少 web 应用。那么,还有 Service Worker 什么事呢?
时至今日,我们终于迎来了 Service Worker 的曙光。简单来说,Service Worker 是一个可编程的 Web Worker,它就像一个位于浏览器与网络之间的客户端代理,可以拦截、处理、响应流经的 HTTP 请求;配合随之引入 Cache Storage API,你可以自由管理 HTTP 请求文件粒度的缓存,这使得 Service Worker 可以从缓存中向 web 应用提供资源,即使是在离线的环境下。
可以看出,Service Worker 被设计为一个相对底层(low-level)、高度可编程、子概念众多,也因此异常灵活且强大的 API,故本文只能展示它的冰山一角。出于安全考虑,注册 Service Worker 要求你的 web 应用部署于 HTTPS 协议下,以免利用 Service Worker 的中间人攻击。笔者在今年 GDG 北京的 DevFest 上分享了 Service Worker 101,涵盖了 Service Worker 譬如「网络优先」、「缓存优先」、「网络与缓存比赛」这些更复杂的缓存策略、学习资料、以及示例代码,可以供大家参考。
Service Worker 的一种缓存策略:让网络请求与读取缓存比赛
你也可以尝试在支持 PWA 的浏览器中访问笔者的博客 Hux Blog,感受 Service Worker 的实际效果:所有访问过的页面都会被缓存并允许在离线环境下继续访问,所有未访问过的页面则会在离线环境下展示一个自定义的离线页面。
在笔者看来,Service Worker 对 PWA 的重要性相当于 XMLHTTPRequest 之于 Ajax,媒体查询(Media Query)之于响应式设计,是支撑 PWA 作为「下一代 web 应用模型」的最核心技术。由于 Service Worker 可以与包括 Indexed DB、Streams 在内的大部分 DOM 无关 API 进行交互,它的潜力简直无可限量。笔者几乎可以断言,Service Worker 将在未来十年里成为 web 客户端技术工程化的兵家必争之地,带来「离线优先(Offline-first)」的架构革命。
Push Notification
PWA 推送通知中的「推送」与「通知」,其实使用的是两个不同但又相得益彰的 API:
Notification API 相信大家并不陌生,它负责所有与通知本身相关的机制,比如通知的权限管理、向操作系统发起通知、通知的类型与音效,以及提供通知被点击或关闭时的回调等等,目前国内外的各大网站(尤其在桌面端)都有一定的使用。Notification API 最早应该是在 2010 年前后由 Chromium 提出草案以 webkitNotifications 前缀方式实现;随着 2011 年进入标准化;2012 年在 Safari 6(Mac OSX 10.8+)上获得支持;2015 年 Notification API 成为 W3C Recommendation;2016 年 Edge 的支持;Web Notifications 已经在桌面浏览器中获得了全面支持(Chrome、Edge、Firefox、Opera、Safari)的成就。
Push API 的出现则让推送服务具备了向 web 应用推送消息的能力,它定义了 web 应用如何向推送服务发起订阅、如何响应推送消息,以及 web 应用、应用服务器与推送服务之间的鉴权与加密机制;由于 Push API 并不依赖 web 应用与浏览器 UI 存活,所以即使是在 web 应用与浏览器未被用户打开的时候,也可以通过后台进程接受推送消息并调用 Notification API 向用户发出通知。值得一提的是,Mac OSX 10.9 Mavericks 与 Safari 7 在 2013 年就发布了自己的私有推送支持,基于 APNS 的 Safari Push Notifications。
在 PWA 中,我们利用 Service Worker 的后台计算能力结合 Push API 对推送事件进行响应,并通过 Notification API 实现通知的发出与处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// sw.js self.addEventListener('push', event => { event.waitUntil( // Process the event and display a notification. self.registration.showNotification("Hey!") ); });
self.addEventListener('notificationclick', event => { // Do something with the event event.notification.close(); });
self.addEventListener('notificationclose', event => { // Do something with the event });
对于 Push Notification,笔者的几次分享中一直都提的稍微少一些,一是因为 Push API 还处于 Editor Draft 的状态,二是目前浏览器与推送服务间的协议支持还不够成熟:Chrome(与其它基于 Blink 的浏览器)在 Chromium 52 之前只支持基于 Google 私有的 GCM/FCM 服务进行通知推送。不过好消息是,继 Firefox 44 之后,Chrome 52 与 Opera 39 也紧追其后实现了正在由 IETF 进行标准化的 Web 推送协议(Web Push Protocol)。
如果你已经在使用 Google 的云服务(比如 Firebase),并且主要面向的是海外用户,那么在 web 应用上支持基于 GCM/FCM 的推送通知并不是一件费力的事情,笔者推荐你阅读一下 Google Developers 的系列文章,很多国外公司已经玩起来了。
从 Hybrid 到 PWA,从封闭到开放
2008 年,当移动时代来临,唱衰移动 Web 的声音开始出现,而浏览器的进化并不能跟上时,来自 Nitobi 的 Brian Leroux 等人创造了 Phonegap,希望它能以 Polyfill 的形式、弥补目前浏览器与移动设备间的「鸿沟」,从此开启了混合应用(Hybrid Apps)的时代。
PWA 作为一个涵盖性术语,与过往的这些或多或少通过私有平台 API 增强 web 应用的尝试最大的不同,在于构成 PWA 的每一项基本技术,都已经或正在被 IETF、ECMA、W3C 或 WHATWG 标准化,不出意外的话,它们都将被纳入开放 web 标准,并在不远的将来得到所有浏览器与全平台的支持。我们终于可以逃出 App Store 封闭的秘密花园,重新回到属于 web 的那片开放自由的大地。
有趣的是,从上文中你也可以发现,组成 PWA 的各项技术的草案正是由上述各种私有方案背后的浏览器厂商或开发者直接贡献或间接影响的。可以说,PWA 的背后并不是某一家或两家公司,而是整个 web 社区与整个 web 规范。正是因为这种开放与去中心化的力量,使得万维网(World Wide Web)能够成为当今世界上跨平台能力最强、且几乎是唯一一个具备这种跨平台能力的应用平台。
当我们说到 PWA 是否被支持时,其实我们在说的是 PWA 背后的几个关键技术都得到支持了没有。以浏览器内核来划分的话,Blink(Chrome、Oprea、Samsung Internet 等)与 Gecko(Firefox)都已经实现了 PWA 所需的所有关键技术(👏👏👏),并已经开始探寻更多的可能性。EdgeHTML(Edge)简直积极得不能更积极了,所有的特性都已经处于「正在开发中」的状态。最大的绊脚石仍然来自于 Webkit(Safari),尤其是在 iOS 上,上述的四个 API 都未得到支持,而且由于平台限制,第三方浏览器也无法在 iOS 上支持。(什么你说 IE?)
不过,也不要气馁,Webkit 不但在它 2015 年发布的五年计划里提到了 Service Worker,更是已经在最近实现了 Service Worker 所依赖的 Request、Response 与 Fetch API,还把 Service Worker 与 Web App Manifest 纷纷列入了「正在考虑」的 API 中;要知道,Webkit 可是把 Web Components 中的 HTML Imports 直接列到「不考虑」里去了……(其实 Firefox 也是)
This slides is powered by Yanshuo.io (演说.io), a online software helping you create, store and share web slides.
There are 2 ways that you can fork or contribute this project:
index.html is the HTML source code exported from Yanshuo.io, and many of its dependencis (js, css, fonts) are still linked to CDN of Yanshuo.io. You can do any secondary development and host it by yourself.
Download the project file under shuo/, drag it into Yanshuo.io, and you are ready to go. You can edit whatever you want, upload it to your account, and even share your distributions.
This slides is powered by Yanshuo.io (演说.io), a online software helping you create, store and share web slides.
index.html is the HTML source code exported from Yanshuo.io, and many of its dependencis (js, css, fonts) are still linked to CDN of Yanshuo.io. You can do any secondary development and host it by yourself.
后面我会说,我认为 React 的 JSX 是非常耀眼的亮点。然而要使用 JSX,你需要选择支持它的工具。尽管 React 已经足够流行,工具支持不再是什么问题,但诸如 IDE 和 lint 工具等新工具还不大可能很快得到支持。Angular 2 的模版是保存在一个字符串或独立的 HTML 文件中的,所以不要求特殊的工具支持(不过似乎 Angular 字符串模版的智能解析工具已经呼之欲出了)。
Web Components 友好
Angular 2 还拥抱了 Web Component 标准。唉,真尴尬我居然一开始忘记提到这点了——最近我还发布了一门关于Web Components 课程呢!简单来说,把 Angular 2 组件转换成原生 Web Components 应该会比 React 组件容易得多。固然 Web Components 的浏览器支持度依然很弱,但长期来看,对 Web Components 友好是很大的优势。
Angular 的实现有其自身的局限和陷阱,这正好让我过渡到对 React 优势的讨论。
React 的优点
现在,让我们看看是什么让 React 如此与众不同。
JSX
JSX 是一种类似 HTML 的语法,但它实际上会被编译成 JavaScript。将标签与代码混写在同一个文件中意味着输入一个组件的函数或者变量时你将享受到自动补全的福利。而 Angular 基于字符串的模版就相形见绌了:很多编辑器都不会高亮它们(只会显示单色)、只有有限的代码补全支持,并且一直到运行时才会报错。并且,通常你也只能得到很有限的错误提示。不过,Angular 的团队造了一个自己的 HTML 解析器来解决这个问题。(叼叼叼!)
而屏幕更大的 iPad Pro 选择了宽 1024px 的 viewport,这使得它天生就能容纳更多的内容。不少人说iPad Pro 就是抄 Microsft Surface Pro 的嘛……嗯哼,IE/Edge 在 Surface Pro 上就是以 1024px 作为视口宽度的……
从交互的角度上来说,iPad Pro 虽然不支持 3D Touch,但是可以搭配 Smart Keyboard 与/或 Apple Pen(带有压力侦测)使用。对于键盘其实并没有什么好说的,如果一个网站在搭配键盘的桌面电脑上好用,它在 iPad Pro 上应该也不赖。而对于 Apple Pen,很可惜,目前似乎并没有 API 能让你在网站上获得这根笔的压力与角度。
新的 iOS 操作系统特性
iPad 上的多任务处理
自 iOS 9 起,iPad 允许两个应用在同一时刻并肩执行,有三种方式:Slide Over,Split View 与 Picture-in-Picture。不过,每一种方式都有其硬件需求,比如说 Slide Over 需要 iPad Air, iPad Mini 2 以上的设备,而 Split View 由于对内存的要求目前只支持 iPad Air 2 与 iPad Pro。
Slide Over(滑过来!)
Slide Over 支持的 App 并不多,不过 Safari 名列其中,这意味着我们的网站将可能在这个模式下被渲染。当网站处于 Slide Over 模式下时,它将在屏幕的右 1/4 位置渲染,并且置于其他 native app 之上。
这个模式也为 Responsive Web Design(响应式网站设计)提出了新的挑战:一个只为 iPad 优化的网站,也需要能在该设备上以无需手动刷新的形式支持小屏幕的渲染。因此,如果你正在使用服务器端探测(RESS),那么你的 iPad 版本需要以某种方式包含手机版本的网站,或者在进入该模式后重新加载一次。(如果你不了解 RESS,你可以观看我的另一篇博文)
尽管有不少人抱怨(大部分都是针对 webview 的缺失),我并不能确定这是不是个坏主意。我猜测 Apple 会尝试通过 Siri 来将 “web” 带给 TV、手表、甚至 CarPlay 的用户。所以,如果你遵循了上述的 “App Search” 的步骤,你的内容将可能通过 Siri 在这些设备上以 widget(小部件)或者快捷回复的形式变得可以访问。
对于 Apple TV ,它支持使用 JavaScript、DOM API 与 XMLHttpRequest 来让我们构建某种类似 Client-Server webapp 的东西。没有 HTML 和 CSS,这是什么把戏?其实它支持的叫 TVML,是一种基于 XML、为那些可以被渲染在 TV 屏幕上的特定内容而优化后的标签。这些标签只可以在来自应用商店的 native app 中渲染,但是这些 TVML 是由服务器端来生成的。