本文讲述浏览器一些实用的API。包含如下内容 Worker、localStorage、 Servlet、Canvas、 Svg。由于浏览器API知识确实很多,本文将以系统概括和deme展示的方式带你快速学习理解这些API。深入掌握请阅读demo源码+多动手练习。

- 由于JS一开始设计的很简单 -- 单线程, JS执行与DOM互斥
- 再加上JS开发的web环境中 -- 使用解释型语言, 运行较慢
- 为了web体验,提出了 Worker方案,
- 将复杂运算 不涉及dom操作的任务放在其它线程中并行处理,进而解决渲染卡顿的问题。
js// main.js
const worker = new Worker('./worker.js')
worker.onmessage = function(e) {
console.log(`收到 web worker 消息 "${e.data}"`, e); // 1
setTimeout(() => {
worker.postMessage('你好,我是主线程,我收到你的消息')
});
}
// worker.js
self.onmessage = function(e) {
console.log(`收到主线程消息 "${e.data}"`, e); // 2
}
self.postMessage('1. 你好,我是web worker');
js// 写法1
self.addEventListener('message', function (e) {
self.postMessage('You said: ' + e.data);
}, false);
// 写法2
self.onmessage('message', function (e) {
self.postMessage('You said: ' + e.data);
}, false);
// 写法3
this.addEventListener('message', function (e) {
this.postMessage('You said: ' + e.data);
}, false);
// 写法4
addEventListener('message', function (e) {
postMessage('You said: ' + e.data);
}, false);
关闭Worker
worker.terminate()self.close()错误处理 主线程可以监听Worker是否发生错误,
js// 主线程
worker.onerror(function (event) {
console.log([
'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join(''));
});
// 或者
worker.addEventListener('error', function (event) {
// ...
});
// worker线程也可以监听错误
self.addEventListener('error', function(e){
console.log('worker线程发生错误', e);
})
jsimportScripts('script1.js');
// 也可以加载多个脚本
importScripts('script1.js', 'script2.js');
window document parent这些对象navigator 和 locationalert()方法和confirm()方法,但可以使用XMLHttpRequest对象发出ajax请求file://),它所加载的脚本必须来自网络更多关于WebWorker: 《Web Worker使用教程》
sessionStorage 与 localStorage的区别是:localStorage可以长期保留, sessionStorage当前会话结束(页面被关闭时)会被清除。 除此之外,它们两的用法及特性几乎一致
localStorage.setItem('myCat', 'tom');或localStorage.myCat='tom';localStorage.getItem('myCat'); 或 localStorage.myCatjs// index.html
CSS.paintWorklet.addModule('paint-grid.js');
// paint-grid.js
registerPaint('transparent-grid', class {
// ...
}}
- 现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过4KB,且每次请求都会发送回服务器;
- LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。
- 所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景
特点:
indexedDB相关概念
对比mysql数据库, 快速上手indexdb

用途:重客户端应用,客户端游戏、chrome扩展开发
入门示例
这个AI助手项目,就是使用indexedDB存储,关于index部分代码很独立,你可以看一些这文件,帮你快速入门indexedDB
本段参考资料:
Canvas 是html5 新增的API
坐标 Canvas画布提供了一个作图的平面空间,该空间每个点都有自己的坐标。
画布
width 和 height 默认画布宽度300px 高度150pxwidth 和 height 属性一致,否则会出现拉伸路径
save() 和 restore()).store()和 .fill()方法会自动闭合路径事件
动画
关于Canvas学习重点在于练习, 先推荐一些学习资料
主要参考上述文章,我写了一些极简demo,demo有详细的注释

感兴趣的同学 点这里, 打开开发者工具看一下源码。
为了使用编辑器API提示效果,demo是使用TS写的,熟悉TS的同学 可以修改文件后缀名就可以查看ts代码, 如 canvas.js canvas.ts
Canvas的用途
SVG是指可伸缩矢量图形
相对于传统图片它有体积小和放大不失真的优势
对比 canvas与svg
| - | Canvas | Svg |
|---|---|---|
| 描述图形方式 | 使用JavaScript描述2D图形 绘制完成浏览器不在关注 位置变更需要重新渲染 | 使用XML描述2D图形。 每个被绘制的图形被称为对象, 对象属性发生变化会重新渲染 |
| 分辨率 | 基于像素绘制,依赖分辨率 | 基于图形绘制,放大不失真 |
| 事件 | 不支持事件处理器,需要手动编程 用户交互到像素 | 支持事件编程 用户交互到路径 |
| 元素 | 单个Canvas元素 | 多种图形元素 |
| 操作 | 只能脚本渲染 | 支持脚本和css |
| - | 能够以 .png 或 .jpg 格式保存结果图像 | 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快) |
| 使用场景 | 适合小面积,大数量应用场景(图像密集型游戏) | 适合大面积小数量应用场景(如google地图) |
主要参考 《终于会用SVG画图了》我写了一些demo

感兴趣的同学 点这里, 打开开发者工具看一下源码。
移动端h5应用,有一些场景 如埋点需求、性能优化(切到后台避免不必要的请求和渲染)需要开发者知道页面切换到后台或者被销毁。
pagehide beforeunload unload 在移动端可能不会被触发
后来HTML5新增了document.visibilityState API
hidden visiable至少一部分可见 prerender页面即将或正在渲染,处于不可见状态由于历史原因还保留document.hidden 仅当document.visibilityState属性返回visible时,它的值时false,其他都是true,包括prerender状态, 所以只要有可能我们都是应该使用document.visibilityState
visibilitychange事件
document.visibilityState 发生改变都会触发 visibilitychange事件总结
visibilitychange事件即可beforeunload事件只有一种适用场景,就是用户修改了表单,没有提交就离开当前页面。开发中有一些场景需要用到IntersectionObserver
注意:
IntersectionObserver是采用 requestIdleCallback()实现,也就是说该API异步执行且优先级很低,如果你滑动过快可能不被触发写不如练, 我这边写了四个关于IntersectionObserver的demo,代码极简且有详尽注释,希望能带你快速掌握IntersectionObserver。

感兴趣的同学 点这里, 打开开发者工具看一下源码。
本段内容主要参考资料 阮一峰 WebAPI 教程
WebComponents 不是单一的规范,而是由一些列技术组成
Custom ElementsTemplateShadow DOMHTML Import 已被废弃使用时,并不一定上面四种 API 都要用到。其中,Custom Element 和 Shadow DOM 比较重要,Template 和 HTML Import 只起到辅助作用。
Custom Elements
customElement.define('my-ele', MyELement) 定义组件customElement.get('my-ele') 获取类, 可以通过new再次创建customElement.whenDefine('my-ele', callback) 定义组件后触发static get observedAttributes 和 attributedChangedCallback 监听属性变化this.dispatchEvent(new CustomEvent('myevent', {detail: ''}))constructor 创建时被调用attributeChangedCallback 当自定义元素的一个属性被添加、移除或修改时,这个方法会被调用。connectedCallback 第一次被连接到文档 DOM 时被调用'adoptedCallback 当自定义元素被移入新文档后调用(需借助iframe演示)disconnectedCallback 当自定义元素从文档中移除时,这个方法会被调用。这时可以进行一些资源清理操作。Template
Shadow DOM
open closed 设置为 open 则JS可以通过element.shadowRoot 属性来访问ShadowDOM内部的结构服务器向客户端推送数据,有很多解决方案。除了“轮询” 和 WebSocket,HTML 5 还提供了 Server-Sent Events(以下简称 SSE)。
服务端向客户端声明,接下来要发送的是流信息,这时客户端就不会关闭连接,会一直等待服务端发送过来的新的数据流
与websocket比较。总体来说WebSocket更强大灵活。因为他是全双工通信
| - | Websocket | SSE |
|---|---|---|
| 通信方式 | 全双工通信 | 单向通信 steaming本质上是下载 |
| 协议 | 基于HTTP升级后的一种新协议 | 使用HTTP协议 |
| 重连机制 | 需要自己实现断线重连 | 默认支持断线重连 |
| 数据类型 | 支持文本、二进制消息 | 一般只用来传输文本,二进制数据需要编码后传送 |
综上 websocket属于重量级武器 SSE属于轻量级武器,两者各有特点,适合不同的场景
关于SSE的学习 推荐这篇文章《Server-Sent Event》
这是参考这篇文章,我写了个nodejs的domo, 可以下载下面两个文件本地运行,体验一下SSE
应用案例
ChatGPT的打字效果就是使用SSE实现的, 略有不同的一点是 在SSE中客户端使用 EventSource构建请求, 而chatGPT 使用的是 fetch请求。
推测原因是 EventSource只能发出GET请求(url长度最多2000字符),且不支持自定义请求头, 而fetch请求要模拟 onopen onmessage onerror事件和close方法,另外要了解stream机制。更多可以参考这篇文章 《chatGPT打自机消息回复机制》
总结: SSE通过借助fetch解除不能自定义header、url长度等限制、跨域等限制。
XMLHTTPRequest对象XMLHTTPRequest 所有输入、输出、状态都在一个接口管理,容易写出非常混乱的代码,而 fetch将它们分散在几个不同的对象上(设计更合理化),另外返回Promise对象(避免嵌套的回调函数)XMLHTTPRequest对象不支持数据流,所有数据必须放在缓存里,等到全部都拿到后,再一次性吐出来。Headers, Request和Response作用
更多关于 MessageChannel 推荐阅读 《浅谈MessageChannel》
共享存储
localStorage
IndexDB + JS定时器查询cookie + JS定时器查询
中介者模式
navigator.serviceWorker serviceWorker优势也十分明显,它位于浏览器主控进程,生存周期比页面长,因此可以存储离线消息BroadCast Channel 该方式很简便,但兼容性方面不乐观SharedWorker + 定时器服务端推送
SSE 有跨域限制, 但可以借助fetch规避websocket 无跨域限制其他
如果是后者通过前者打开 还可以使用 open/opener方式
关于具体实现方案,推荐阅读 《面试官:前端跨页面通信,你知道哪些方法?》
主页面和iframe之间的通信
postMessageMessageChange在DOM3中定义了Mutation events该API是同步执行,由于它本身是事件所以捕获采用事件冒泡的机制,如果捕获期间由触发了其他的Mutation Events的话,很可能就导致JS主线程阻塞,甚至是浏览器崩溃。
为解决 Mutation events 同步执行和事件冒泡的问题, DOM4定义了Mutation Observer用于取代Mutation events。它采用异步执行,每次变更记录在消息队列中,最后统一执行
更多关于 MutationObserver 推荐阅读 《MutationObserver用法总结》
这里主要是借助 前端文件压缩上传、下载的案例来学习 Blob File FileReader Blob URL Canvas FormData之间的联系
先来看一下它们之间的关系图

Blob 与 File
Blob 二进制大文件对象 只读, File 继承自 Blob<input type='file'>得到的就是File对象new File 可转换为File文件Blob URL 是一种伪协议,允许 Blob 和 File 对象用作图像,下载二进制数据链接等的 URL 源。
blob:<origin>/<uuid> 可借助<a>下载URL.createObjectURL(file) 转换为Blob URLBlob URL可以借助new File([Blob], fileName, {type})转换为 FilefileData.slice(0, fileData.size, fileData.type); File 转 BlobCanvas
ctx.drawImage(imgEle)对图像进行复制、压缩尺寸、剪裁展示等canvas.toBlob进行图片格式转换及压缩。FileReader
File或Blob转换为base64FormData 表单上传的一种方式 Content-Type: multipart/form-data 用于上传含有文件的表单FormData formData.append("file", file);base64 通过 FileReader 将File或Blob转换为base64<a>和Blob URL下载ArrayBuffer 累了,以后在学这里我写了一个 图片压缩上传下载 案例
本文作者:郭敬文
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!