💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # Web应用程序 ## ApplicationCahe 通过缓存清单文件以及 ApplicationCache API,就能够控制缓存文件。 ### 缓存清单文件的创建 在 html 标签的 manifest 属性中指定缓存清单文件的路径。通过 text/cache-manifest 这一 MINE Type 来发布缓存清单文件。在缓存清单文件所在的同一文件夹内创建一个名为 .htaccess 的文件并记录 AddType 目录信息,以设定支持特定扩展名的 MIME Type。 ```html <!DOCTYPE HTML> <html manifest="sample.appcache"> .... </html> ``` .htaccess 实例 ``` AddType text/cache-manifest .appcache ``` sample.appcache 实例 ``` CACHE MANIFEST # revision 1 CACHE: ./cache.js ./cache.css ``` ### 缓存更新 通过注释插入版本号或是更新日期,就能实现对缓存清单文件的更新了 ``` CACHE MANIFEST # revision 2 CACHE: ./cache.js ./cache.css ``` ### 对缓存更新的确认 可以通过 `applicationCache.update` 方法在启动页面意外的任意时刻执行对缓存更新的确认。 ### 在线与离线 通过引用 `navigator.onLine` 来获知网络连接状态。还可以通过 online/offline 事件来监听连接状态的切换时机 # 与桌面应用的协作 ## File API File API 是一种用于获取在本地保存的文件的信息与内容的 API。 ### FileReader 通过 FileReader 就可以读取文件的内容。 ```javascript var reader = new FileReader(); ``` FileReader 的方法 方法 | 说明 ---|--- readAsArrayBuffer(blob) | 以 ArrayBuffer 的形式读取文件 readAsBinaryString(blob) | 以二进制字符串的形式读取文件 readAsText(blob[,encoding]) | 以文本形式读取文件 readAsDataURL(blob) | 以 DataURL 的形式读取文件 abort() | 中止读取 FileReader 的事件处理程序 事件 | 说明 ---|--- onloadstart | 读取开始 onprogress | 读取中 onload | 读取成功 onerror | 读取失败 onabort | 读取中止 onloadend | 读取结束(无论成功还是失败) ### 对错误的处理 通过 `onerror` 事件处理程序来捕捉读取的错误,错误原因可以通过 error.code 属性来获取 error.code 属性 属性名| 值 | 说明 ---|---|--- NOT_FOUND_ERR | 1 | 没有找到文件 SECURITY_ERR | 2 | 安全性错误 ABORT_ERR | 3 | 文件的读取被中止 NOT_READBLE_ERR | 4 | 没有文件的读取权限 ENCODING_ERR | 5 | 超过了 DataURL 的尺寸限制 ### 读取中的处理 通过 `progress` 事件来获知读取的进度 属性名 | 说明 ---|--- lengthComputable | 如果文件的长度能够被计算则为 true,否则为 false loaded | 已经被读取的数据尺寸 total | 读取目标的文件尺寸 ### 读取文件的一部分 通过 `slice` 方法来实现文件的部分读取。返回值为 Blob 对象。 ```javascript // 读取的开始位置 var lastPos = 0; function getDiff(file) { // 从上一次的读取位置起,切换之后的部分 var blob = file.slice(lastPos, file.size); // 保存本次读取的位置 lastPos = file.size; var reader = new FileReader(); reader.onload = function(){...}; reader.readAsText(blob); } ``` ### FileReaderSync 同步读取文件内容的 API # 存储 ## localStorage 与 sessionStorage localStorage 与 seeionStorage 的区别在于数据的生命周期。对于 localStorage 中保存的数据来说,只要没有被显示的地删除,即使浏览器或计算机执行了重启,这些数据也不会丢失。 ## sessionStorage 的生命周期 共享 sessionStorage 的情况 - 通常的页面跳转时 - 在 iframe 内打开了子页面 - 从奔溃中恢复时 - 重新载入时 没有共享sessionStorage 时 - 在新窗口或新标签页中打开了页面 - 窗口被关闭后又被重新打开时 ## 多个标签之间的数据同步 对于多个标签之间数据不一致的问题,则必须在合适的时机将本地变量中的数据写入 localStorage 之中以进行同步。这时需要捕获 storage 事件,在其他标签页中执行的 localStorage 更新操作同步至本地变量。 ```javascript // 在更改设定是将其写入 localStorage function setStorage(key, value){ storage[key] = value; localStorage[SERVICE_NAME] = JSON.stringify(storage); } // 将在其他标签页中进行的 localStorage 更改读入本地变量 window.onstorage = function(event){ if(event.key === SERVICE_NAME && event.newValue){ storage = JSON.parse(event.newValue); } } ``` ## Indexed Database 在浏览器中通过 JavaScript 进行操作的功能强大数据库。提供创建用于检索的索引及事务的功能。 [参考地址](https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API) # WebSocket WebSocket 是一种用于在服务器与客户端之间实现高效的双向通信的机制。通过 WebSocket,就能够在1个 HTTP 连接上自由地双向收发消息。与通过结合使用 XMLHTTPRequest 与 Server-sent Events 而实现的双向通信相比,这种方式具有通信效率更高、设计与实现容易等优点。 ## 长轮询 一种只有在必要时才从服务器返回响应的方式。在客户端发送请求之后,服务器将会保留响应,并维持连接,因此可以在任意的时间点从服务器返回响应。而客户端在收到了响应的同时,将会再次向服务器建立连接。 ## 流 通过由客户端发出的第一个请求,建立连接,并在维持该链接的同时从服务器不断向客户端返回响应。由于服务器端始终处于在发送响应的状态,因此将这种方式称为流。 ## WebSocket 的执行方式 通过 WebSocket 开始双向通信时,首先需要与服务器建立连接。而用于建立连接的请求,是由客户端通过 HTTP 方式发送的。服务器将会确认连接对象的源以及协议,并发送连接许可的响应。在发送了响应之后,浏览器将会把该连接升格为 WebSocket。这一连串的流程称为握手。 此外,仅在握手时才会在通信中添加 HTTP 头部,因此有必要在握手时,执行所有使用了 UserAgent 或 Cookie 来进行的用户及设备认证。 ### 连接的建立 需要在客户端执行对 WebSocket 类的构造函数调用。构造函数调用的第1个参数所指定的是将要进行连接的 WebSocket 服务器的URL,而其第2个参数则需要指定子协议名。 ```javascript var ws = new WebSocket('ws://www.foo.org:8888/bar', 'subprotocol'); ``` WebSocket 可以选择 `ws://` 或 `wss://` 这两种协议。如果将协议指定为 `wss`,就能够以 TLS 对通信加密。如果没有指定端口,则将分别默认使用 80 和 443 端口。 在进行构造函数调用之后,内部将会执行握手处理。一旦建立了连接, WebSocket 实例中就会触发 `open` 事件。 ### 消息的收发 要将消息发送至服务器,则需要将希望发送的数据传递至 `send` 方法的参数。如果要从服务器接收消息,则可以通过 `message` 事件对其进行捕捉。由服务器发送的数据会保存于 `message` 事件对象的 `data` 的属性之中。 ```javascript // 向服务器发送消息 ws.send('Hello, WebSocket!'); ws.onmessage = function(event) { // 取出所收到的数据 var receivedMessage = event.data; } ``` ### 连接的切断 可以通过在客户端调用 `close` 方法,来显示地切断连接。 ```javascript ws.close(); ws.onclose = function(event) { ... } ``` ### 连接的状态确认 通过引用 WebSocket 实例的 readState 属性,来确认连接的状态。 属性 | 整数值 | 说明 ---|---|--- CONNECTING | 0 | 正在连接 OPEN | 1 | 已处于连接中 CLOSING | 2 | 正在切断连接 CLOSED | 3 | 已经切断或连接失败 # Web Workers Web Workers 是一种能够在另外的线程中创建新的 JavaScript 运行环境,以使 JavaScript 代码能够在后台处理的一种机制。如果能够视情况恰当地分离出复杂的处理,并将其置于后台运行,就能够在通过客户端进行复杂处理的同时,不妨碍用户的 UI 操作,从而开发出高可用性的 Web 应用程序。 ## Web Workers 的执行方式 将客户端运行环境称为主线程,将通过Web Workers 创建的后台运行环境称为工作线程。可以在主线程中创建工作线程,且能够同时创建多个工作线程。 主线程与工作线程的运行环境是相互分离的,无法相互引用对方环境中的变量。 工作线程的环境中无法引用 document 对象。如果要进行数据的收发处理,则必须通过消息收发接口(`postMessage`和`message`)来进行。 ## 工作线程的创建 在主线程中调用 Worker 构造函数来创建工作线程。 ```javascript var worker = new Worker('worker.js'); ``` ## 主线程一侧的消息收发 ```javascript worker.postMessage('foo'); worker.onmessage = function(event) { var receivedMessage = event.data; ... } ``` ### 工作线程一侧的消息收发 ```javascript postMessage('foo'); onmessage = function(event) { var receviedMessage = event.data; ... } ``` ### 工作线程的删除 ```javascript // 在主线程中删除 worker.terminate(); // 在工作线程中删除 close(); ``` ### 外部文件的读取 ```javascript importScripts('http://www.foo.org/external.js', 'dependent.js'); // 此时,外部 JavaScript 文件中的内容以及被分析求值 ``` ## 共享工作线程 1个工作线程可以被多个页面共享引用。为了区分于通常的工作线程,这种类型的工作线程被称为“共享工作线程”。能够同时在多个不同的窗口之间引用同一个共享工作线程。可以通过共享工作线程来实现窗口间的消息收发,或者以共享工作线程作为中转,将服务器连接相整合。 ### 共享工作线程的创建 调用 `SharedWorker` 类的构造函数来创建共享工作线程。第1个参数和通常的工作线程一样,需要制定一个 JavaScript 文件的 URL,第2个参数所指定的则是该共享工作线程的名称。以同样的文件及名称创建的话,则会返回一共引用了相同共享工作线程的 `SharedWorker` 实例。 ```javascript // 创建共享工作线程 var worker = new SharedWorker('worker.js', 'text-worker'); ``` ### 共享工作线程的消息收发 使用共享工作线程进行消息的收发时,其内部使用了信道通讯,一种通过名为 MessagePort 的成组对象进行消息收发的机制。 在主线程中进行消息收发 ```javascript // 创建共享工作线程 var worker = new SharedWorker('http://www.a.com/worker.js'); // 通过 MessagePort 发送消息 worker.port.postMessage('foo'); // 通过 MessagePort 接收消息 worker.port.onmessage = function(event){ var receivedData = event.data; ... } ``` 在工作线程中进行消息收发 ```javascript // 来自于主线程的连接请求 onconnect = function(connectEvent) { // 获取连接请求方的 MessagePort var port = connectEvent.ports[0]; // 通过 MessagePort 发送欢迎消息 port.postMessage('hello'); // 通过 MessagePort 接收消息 port.onmessage = function(messageEvent) { // 将所接收的数据直接回复 port.postMessage(messageEvent.data); } } ``` ### 共享工作线程的删除 ```javascript // 在主线程中关闭连接 worker.port.close(); // 在共享线程中关闭 close(); ```