注意那些 Promise 反模式

JavaScript Promise 异步 回调函数 设计模式

JavaScript 作为天生的客户端脚本,编写异步逻辑有着天然的优势, 比如嵌套函数(很自然的闭包机制),事件模型(多数宿主都有提供),回调函数(函数是一等公民)。 Promise 用来更好地组织异步代码, 与其他设计模式类似,未能理解其设计意图之前容易误用和滥用。本文列举其中常见的反模式。

读者有更精彩的反模式例子,欢迎评论或者邮件。本文中的代码仅用于示例,未必存在这样的接口。

继续阅读

Promise 回调的执行

JavaScript Promise 异步

Promise 是 JavaScript 中处理异步的一种模式, 可以大幅简化异步代码和增加可读性,基于 Promise 的单元测试 也更加可读。 本文参考了 Promises/A+ECMA 2015 等文档, 测试了 Bluebird, Chrome 58.0.3029.110,Node.js 6.9.2 等环境,给出 Promise 异步行为。

TL; DR

  • Promise.prototype.then 传入的回调会在 NextTick(异步)执行
  • 构造 Promise 时传入的 executor 会立即执行
  • Promise 的各种实现表现一致
继续阅读

百分号编码与 encodeURIComponent

encodeURIComponent UTF-8 URI URL GB2312

百分号编码、encodeURIComponent、URL encode 其实都是指在 URL 参数中转义任意字符。 在百分号编码中,每个字符被编码成3个字符,包括第一个起始的 %, 以及接着的两个字符表示 16 进制的一个字节。 比如空格字符(00100000)编码后的结果为 %20

TL;DR

  • URL 是 URI 的一种形式。
  • URI 的合法字符包括18个保留字符和66个非保留字符
  • application/x-www-form-urlencoded 中空格编码为 +
  • decodeURIComponent() 对非 UTF-8 的源会抛出 URIError: URI malformed
继续阅读

内联和外链脚本的性能实验

Chrome DNS HTTP JavaScript inline 性能 缓存

HTML 中引入 CSS 和 Script 是为了分离内容、样式和脚本。但有时出于性能考虑可能会内联(一部分)脚本和样式。内联可以减少请求,但外链可以更好地利用HTTP 缓存。 本文通过实验来验证这两种脚本引入方式的渲染性能差别,同时考虑文件数目、网络耗时的影响。

TL;DR

推荐总是使用外链脚本并尽可能利用 HTTP 缓存。除了整体性能较高外,外链脚本符合关注点分离的原则维护性更好。为减小没有缓存时的请求数量,可按更新频率合并脚本文件。 以下是实验结论:

  • 不考虑网络耗时的情况下,内联脚本的 HTML 解析和渲染时间更长,达到可交互状态也需要更长的时间。
  • 无缓存的情况下文件数目的增多会急剧增加渲染时间,但只要合适地使用缓存,即使文件数目非常多也不会影响渲染性能。
  • 在各种网络情况下即使没有缓存,少量的外链和内联脚本的渲染性能表现非常相近。
继续阅读

Fetch API 简介

CORS Chrome Cookie PWA 缓存 跨域 兼容性 Service-Worker

随着 PWA 进入人们的视野,Fetch 作为除了 AJAX 之外的第二个 JavaScript HTTP API 开始引起人们的关注。 Service Worker 中通常利用该 API 进行真正的网络请求并应用相应的缓存策略。 本文简要介绍 Fetch API 的使用,Service Worker 与 Window 中的实现差异,以及跨域 Fetch 的问题。

目前 Web 异步应用都是基于 XMLHttpRequest/ActiveXObject 实现的, 这些对象不是专门为资源获取而设计的,因而它们的 API 非常复杂,同时还需要开发者处理兼容性问题。 虽然开发者普遍使用 $.ajax() 这样的上层包装,但 Fetch API 意在提供更加方便和一致的原生 API, 同时统一 Web 平台上的资源获取行为,包括外链脚本、样式、图片、AJAX 等等。

继续阅读

Service Worker 更新机制

Chrome HTTP 缓存 进程 浏览器 Service-Worker PWA

Service Worker 用来控制页面资源缓存,那么sw.js文件本身如何进行更新呢? 立即使用 Service Worker! 中介绍了使用 Service Worker 搭建离线 App, 以及这一 App 的版本更新方式。 本文重点关注 Service Worker 本身的更新机制,相关标准,以及最佳实践。

Service Worker 更新

Service Worker 作为离线缓存的核心,它的更新意味着 App 版本的更新。 它的更新是由浏览器触发、在独立进程中进行的。

  • 独立的更新进程。安装和更新进程都是独立的进程,渲染进程和当前的 Service Worker 会同时启动,安装和更新不影响用户使用当前 App,这里 Web App 比 Native 更加轻量。
  • 零客户端时更新。为了不打扰用户,只有在用户关闭了所有旧版页面之后(因为 Service Worker 是 shared worker)新的 Worker 才会被激活。
  • 更新过程(Soft Update)由浏览器触发,只有逐字节比对不同时才会启动 更新算法(Update Algorithm)。
继续阅读