基础技术简介
Promise:
1、ES6 引入的一种异步编程的解决方案,通过 Promise 对象来提供统一的异步状态管理方法
2、一般在使用 Promise 对象的时候,首先需要对其进行实例化
3、实例化的 Promise 对象为异步状态的管理容器,resolve()和reject()是用于控制 promise 状态的方法
4、在调用 resolve()和reject()方法的时候可传入任意值,这个值会作为监听状态变更的回调函数的参数透传出去
5、Promise 提供了 .then(onFulfilled, onRejected) 和 .catch(onRejected)等
原型链方法用于注册状态变更所触发的回调函数
let promise = new Promise((resolve, reject) => { if (/* 操作成功 */) { resolve(value) } else { reject(error) } })
Promise 状态:
1、'pending':初始状态,代表异步过程仍在进行中,尚未判定成功或者失败
2、'fulfilled':操作成功,通过调用 resolve() 方法,promise 状态将由 'pending' 变更为 'fulfilled'
3、'rejected':操作失败,通过调用 reject() 方法,promise 状态将变更为 'rejected'
Promise 的可靠性:
1、统一格式:经过 Promise 包装的异步过程将具有统一的状态变更方式,统一的 API 以及统一的回调函数格式
2、状态不受外部影响:只能通过 resolve() 和 reject()方法控制 Promise 的状态,这个状态无法被外部直接访问,
也没有提供任何方法从外部修改状态
3、状态具有确定性:从初始状态(pending)变更为执行成功(fulfilled)或者执行失败(rejected),
那么这个状态就被完全确定下来了,不会被后续的任何操作所影响
4、回调函数是一次性的:至多触发一次,规避了过去基于回调函数的异步编程当中回调函数执行次数不受控制的问题
5、不存在回调过早问题:如果回调函数在状态变更前注册,则会等待状态变更时触发;当注册时状态已经确定下来,
那么 Promise 会立即调用这个函数并传入相应的返回值
6、回调函数间不相互影响:同一个 Promise 上注册的回调函数彼此相互隔离,
因此个别回调函数执行出错并不会影响到其他回调函数的正常执行
7、回调函数执行的时序是确定的
Promise 的串行执行与链式调用:
1、Promise.prototype.then:
(1).then(onFulfilled, onRejected) 是 Promise 的原型链方法,用于注册 Promise 对象状态变更时的回调函数
(2)它接受两个回调函数作为参数,分别在 Promise 变更为不同状态时触发,其中 onRejected 可以缺省
(3).then() 方法会创建并返回一个新的 Promise 对象(用 p2 指代,当前监听的 Promise 对象用 p1 指代),
用于表征回调函数的执行情况,这个过程满足如下规则:
a、p1 的状态只决定了何时执行回调以及执行那种类型的回调,并不会影响到 p2 状态
b、p2 的初始状态为 'pending',当回调函数执行成功时状态变更为 'fulfilled',
如果回调执行过程抛出异常则变更为 'rejected'
c、回调函数的返回值 value 将作为 p2 触发状态变更时 resolve(value) 的参数将其传递下去
2、Promise 的链式调用:
(1)可非常直观地将多个需要按顺序执行的异步过程以一种自上而下的线性组合方式实现,
在降低编码难度的同时,也增加了代码的可读性
(2)基于注册在同一 Promise 对象的回调函数彼此互不干扰的特性,我们可以在任何需要的地方进行链分叉
3、Promise 并行执行与管理:
(1)基于 Promise 的异步任务串行执行,本质上是通过 .then()方法去控制上一个异步任务
完成之后再触发下一个异步任务的执行
(2)只需要同步地创建这些异步任务,并对它们的 Promise 对象进行相应的管理即可改造成并行执行
function getX() { return new Promise(resolve => { setTimeout(() => { resolve(1) }, 3000) }) } function getY() { return new Promise(resolve => { setTimeout(() => { resolve(10) }, 5000) }) } function getXAndY([promiseX, promiseY]) { let results = [] return promiseX .then(x => { results.push(x) return promiseY }) .then(y => { results.push(y) return results }) } getXAndY([ getX(), getY() ]) .then(results => { // 5s 后输出 11 console.log(results[0] + results[1]) })
(3)Promise 已经提供了 Promise.all() 方法来实现与上述 getXAndY 一样的功能(一种并行状态管理的方案)
(4)Promise.race() 方法,用于获取第一个发生状态变更的 Promise 对象
Fetch API:
1、Fetch API 首先提供了网络请求相关的方法 fetch(),其次还提供了用于描述资源请求的 Request 类,以及描述
资源响应的 Response 对象,这样就能够以一种统一的形式将资源的请求与响应过程应用到更多的场景当中
2、fetch() 需要传入一个 Request 对象作为参数,它会根据 Request 对象所描述的请求信息发起网络请求
3、fetch() 还支持传入请求 URL 和请求配置项的方式,它会自动根据这些参数实例化 Request 对象之后再去发起请求
fetch(new Request('/path/to/resource', {method: 'GET'})) // 等价于 fetch('/path/to/resource', {method: 'GET'})
4、fetch() 会返回 Promise 对象,当请求响应时 Promise 执行 resolve 并传回 Response 对象
5、fetch() 只有在网络错误或者是请求中断的时候才会抛出异常,此时 Promise 对象会执行 reject 并返回错误信息,
而服务端返回的 HTTP 404、500 等状态码并不认为是网络错误,需要检查 Response.status、Response.ok
等属性以确保请求成功响应
fetch('/path/to/resource').then(response => { if (response.status === 200) { // 请求成功 } else { // 请求失败 } }) .catch(err => { // 网络请求失败或请求被中断 })
Request:
1、Request 是一个用于描述资源请求的类,通过 Request() 构造函数可以实例化一个 Request 对象
2、语法格式:let request = new Request(input, init)
注:input 代表想要请求的资源,可以是资源的 URL,或者是描述资源请求的 Reqeust 对象;
init 为可选参数,可以用来定义请求中的其他选项
3、发送请求:
(1)GET 请求,请求参数需要写到 URL 当中
(2)POST 请求,请求参数需要写到 body 当中
(3)自定义请求的 Headers 信息
(4)设置发起资源请求时带上 cookie
// GET 请求 let getRequest = new Request('requestUrl?name=lilei', { method: 'GET' }) // POST 请求 let postRequest = new Request('requestUrl', { method: 'POST', // body 可以是 Blob、FormData、字符串等等 body: JSON.stringify({ name: 'lilei' }) }) // 自定义请求的 Headers 信息 let customRequest = new Request('requestUrl', { // 这里展示请求 Content-Type 为 text/plain 的资源 headers: new Headers({ 'Content-Type': 'text/plain' }) })
4、常见属性:
(1)url:String 类型,只读,请求的 url
(2)method:String 类型,只读,请求的方法,如 'GET','POST' 等
(3)headers:Headers 类型,只读,请求的头部,可通过 get() 方法获取 'Content-Type','User-Agent' 等信息
//设置发起资源请求时带上 cookie let cookieRequest = new Request('requestUrl', { credentials: 'include' }) if (request.url === 'https://example.com/data.txt') { // ... } if (request.method === 'POST') { // ... } if (reuqest.headers.get('Content-Type') === 'text/html') { // ... }
Response:
1、Response 类用于描述请求响应数据,通过 Response() 构造函数可以实例化一个 Response 对象
2、语法格式:let response = new Response(body, init)
注:body 参数代表请求响应的资源内容,可以是字符串、FormData、Blob 等等;
init 为可选参数对象,可用来设置响应的 status、statusText、headers 等内容
3、在实际应用当中,我们一般会通过 fetch()、Cache API 等等获得请求响应对象,然后再对响应对象进行操作
4、Response 对象的相关属性:
(1)status:Number 类型,包含了 Response 的状态码信息,开发者可以直接通过 status 属性进行状态码检查,
从而排除服务端返回的错误响应
(2)statusText:String 类型,包含了与状态码一致的状态信息,一般用于解释状态码的具体含义
(3)ok:Boolean 类型,只有当状态码在 200-299 的范围时,ok 的值为 true
5、读取响应体:
(1)text():解析为字符串
(2)json():解析为 JSON 对象
(3)blob():解析为 Blob 对象
(4)formData():解析为 FormData 对象
(5)arrayBuffer():解析为 ArrayBuffer 对象
6、Response 提供了 clone() 方法来实现对 Response 对象的拷贝
Fetch API 与 XHR 对比:
1、Fetch API 的异步机制更为先进
2、Fetch API 更为简洁
3、Fetch API 的应用范围更广
Cache API:
1、兼容性检测:在主线程或者 Worker 线程中通过判断全局变量 caches 是否存在来检测浏览器是否支持 Cache API
if ('caches' in self) { console.log('当前环境支持 Cache API') }
2、打开 Cache 对象:通过 caches.open() 方法可以打开一个 Cache 对象,cacheName 表示要打开的 Cache 对象的名称。
该方法是异步方法,返回的 Promise 对象在 resolve 时会返回成功打开的 Cache 对象
caches.open(cacheName).then(cache => {/* 获得 Cache 对象 */})
3、添加缓存:Cache 对象提供了 put()、add()、addAll() 三个方法来添加或者覆盖资源请求响应的缓存
这些添加缓存的方法只会对 GET 请求起作用
4、查找缓存:cache.match() 和 cache.matchAll() 可以实现对缓存的查找
5、获取匹配的请求:通过 cache.keys() 方法实现
6、删除缓存:通过 cache.delete() 方法可以实现对缓存的清理