Promise
Promise两个常用的静态方法:
- all:同时处理多个Promise,等所有的Promise都返回结果后,才会拿到结果,拿到的结果是一个数组,里面包含了所有的Promise的结果,顺序和发送时一致
- race:同时处理多个Pormise,只要有一个Promise返回结果了,那么就会拿到这个结果,也就是说,拿到结果是最先返回的Promise的结果,注意:其他的Promise也会去执行,只不过不会拿它们的执行结果而已
- 补充说明:
- 实例方法,是通过new关键字创建出来的实例调用的方法
- 静态方法,不需要new实例,可以直接通过构造函数调用的方法
FetchAPI
FetchAPI 是标准化组织提供的新型异步请求解决方法,支持Pormise,可以理解成原生的ajax方案(XMLHttpRequest,简称:XHR)的替代版
Axios
Axios,中文网:
-
FetchAPI相比较传统的XMLHTTPRequest是牛x点了,但是在编码时,还是不太舒服,而jQuery专攻DOM操作,不是一个纯粹的ajax请求库,所以,就目前而言用axios还是最好的,企业中也用得最多,node也支持axios,统一了浏览器端和node的写法。
-
基本用法:
// 注意:这里的res形参是约定俗成的,是response的意思,里面是与本次请求相关的响应信息,并不是最终的响应数据 axios.get('http://localhost:3000/someapi').then((res) => { console.log(res.data) // 通过res.data获取最终的响应数据 })
-
常用API:
- get:获取
- delete:删除
- post:添加
- put:修改
-
传参:
-
get|delete:
- 语法:
axios.get|delete(url, config)
- get和delete语法都一样,仅方法名不一样
- x-www-form-urlencoded:
/someapi?name=zs&age=18
- RestFul:
/someapi/zs/18
- params选项:
axios.get|delete(url, { params: { name: 'zs', age: 18 } })
- 这种方式和x-www-form-urlencoded是一样的,二者推荐使用这个
- 补充说明:其实x-www-form-urlencoded和RestFul可以混合使用,比如:
/someapi/zs?age=18
- 语法:
-
post|put:
-
语法:
axios.post|put(url, data, config)
-
post和put语法都一样,仅方法名不一样
-
请求地址都支持x-www-form-urlencoded和RestFul的形式
-
传递参数时,和get与delete有区别,第二个参数直接就是请求数据,如:
axios.post|put(url, { name: 'zs', age: 18 }, config)
,而get与delete的第二个参数是配置对象,配置对象里面的params选项才是真正的x-www-form-urlencoded形式的请求数据,而post和put的第三个参数才是配置对象 -
JSON:
axios.post|put(url, { name: 'zs', age: 18 })
-
x-www-form-urlencoded:
const data = new URLSearchParams() data.append('name', 'zs') data.append('age', 18) axios.post|put(url, data)
-
-
-
响应结果(axios将真正的响应数据包装在响应结果对象中了):
- data:实际的响应数据
- status:HTTP状态码
- config:axios相关配置对象
- headers:响应头信息
- statusText:响应文本信息
-
全局配置:
- timeout:不是延迟发送ajax请求的时间,而是响应超时时间,单位(毫秒),也就是说,如果请求发出去后,在指定的时间内还没有响应,那么就GG了
- baseURL:基准请求地址,可以统一管理基准请求地址,快速切换请求服务器,在变更后台接口环境的时候,很方便,配置了基准请求地址,在每次调用axios API 发送ajax请求时,就无须携带请求地址前缀了。
- headers:请求头信息,通常用来发送token令牌
-
拦截器(可以在这里处理一些公共的业务)
- 请求拦截器:
- 语法:
axios.interceptors.request.use((config) => { return config }, (err) => {})
- 配置了请求拦截器后,在每个请求发出去之前都会先进入请求拦截器
- 可以在请求拦截器的成功函数中获取的当前的配置对象config,在这里可以基于现有的config做一些修改,返回值会作为最终的请求配置
- 语法:
- 响应拦截器:
- 语法:
axios.interceptors.response.use((res) => { return res }, (err) => {})
- 配置了响应拦截器后,在每个请求响应之前都会先进入响应拦截器
- 可以在响应拦截器的成功函数中获取当前的响应结果,可以在这里,基于现有响应结果做调整或格式化,返回值会作为最终的响应结果(不建议在响应拦截器中把部分响应信息吃掉,比如只返回res.data,如果需要获取到除了响应数据之外的其他结果,就不友好了)
- 语法:
- 请求拦截器:
-
异步函数(ES7添加的):
-
async关键字:
- 在普通函数前面加上
async
关键字,该普通函数就变成了异步函数 - 异步函数的返回值会被包装成一个
Promise
实例- 用
return
传递正确的结果,相当于Promise里面的resolve函数 - 用
throw
传递错误的结果,相当于Promise里面的reject函数,一旦抛出错误,后面的代码就不会执行了
- 用
- 在普通函数前面加上
-
await关键字:
-
await后面一般跟Promise实例(其实也可以跟其他的数据,如果是其他的数据,则直接返回),await可以阻塞后续的代码执行,等待Promise实例返回结果后,再继续向下执行
-
await可以直接拿到Promise实例的正确结果,错误结果需要用
try ... catch
或catch(err => err)
(推荐用这个)来获取 -
await关键字只能出现在异步函数(亲爸爸)中
-
范例:用async、await关键字改造依次读取1.txt、2.txt、3.txt文件的代码:
// const fs = require('fs') // promiseify可以将node中现有的基于回调函数形式的异步API,改造成返回Promise实例的函数 // const { promiseify } = require('util') // fs.readFile('./1.txt', 'utf8', (err, data) => { ... }) // const readFileOfPromise = promiseify(fs.readFile) // 这个promises里面的方法都是经过Promise化后的 const { readFile } = require('fs').promises (async () => { const data1 = await readFile('./1.txt', 'utf8') /** setTimout(() => { // 在这里不能用await,因为亲爸爸函数不是异步函数,即使爷爷辈函数是异步函数也不行 await ... }, 1000) */ console.log(data1) const data2 = await readFile('./2.txt', 'utf8') console.log(data2) const data3 = await readFile('./3.txt', 'utf8') console.log(data3) })() // Promise的搞法,相比async/await来说,复杂一些 readFile('./1.txt', 'utf8').then(data1 => { console.log(data1) return readFile('./2.txt', 'utf8') }).then(data2 => { console.log(data2) return readFile('./3.txt', 'utf8') }).then(data3 => { console.log(data3) })
-
-
补充说明:以后我们能用async/await的地方就用async/await,Promise语法一般不用,除了需要使用Promise自己封装一些异步API时以外,例如:封装一个基于Promise的延迟函数
// 第一版 function delay(ms) { return new Promise((resolve, reject) => { setTimeout(() => { resolve() }, ms) }) } // 第二版 和 第一版等价 function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } // 第三版 和 第二版等价 const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) ;(async () => { await delay(3000) console.log('这句代码将在3000毫秒后调用') })()
-
编码时,适当的用空行来分隔不同功能的代码块,也是良好的编程习惯,可以增加代码可读性