二、Promise
- 如果异步任务有两个结果,成功或失败,怎么办?
1.两个结果怎么办?
- 方法一:回调接受两个参数
约定:每一个回调第一个参数是失败的error,第二个参数是成功的结果
fs.readFile('./1.txt',(error,data)=>{//读本地文件
if(error){ console.log('失败');return }
console.log(data.toString())//成功
})
- 方法二:搞两个回调
- 前面函数是成功回调,后面函数是失败回调
ajax('get','/1.json',data=>{},error=>{})
- 接受一个对象,对象有两个key表示成功和失败
回调不一定要用函数,还有可能是对象
ajax('get','/1.json',{
success:()=>{},fail:()=>{}
})
2.以上方法的不足(记下来,表现promise更好)
- 不规范,名称只是随便的约定而已,五花八门。
有人用 success + error,有人用 success + fail,有人用 done + fail, - 容易出现回调地狱,代码变得看不懂
- 很难进行错误处理
2.1 回调地狱
- Node.js应用里面回调地狱非常常见
- 因为Node.js默认的API全是异步的
- 波动拳(Hadoken)
3.解决问题
- 规范回调的名字或顺序
- 拒绝回调地狱,让代码可读性更强
- 很方便捕获错误
4.以AJAX的封装为例
来解释Promise的用法
4.1 原始调用方法
- ajax接收:两个参数和一个回调
其中 options 是回调 - 析构赋值:
const { success, fail } = options
意思是从options里拿出success和fail两个回调
等价于:
const success = options.success
const fail = options.fail
- 封装函数调用ES6简写为:
左边的success是 funciton 缩写(success后省略了冒号和function),右边的fail是箭头函数
//封装函数定义:略
ajax('get','/xxx',{
success(response){},fail:(request,status)=>{}
})
4.1 改成Promise写法
- 调用代码
ajax('get','/xxx')
.then((response)=>{},(request)=>{})
- 通过 .then 传成功和失败的回调
1.then:接收两个参数,前者是成功,后者是失败
2.promise规定:成功和失败回调都只能接收一个参数
3.如果成功了就拿到response,如果失败了就拿到request ajax('get','/xxx')
返回了啥?
1.之前的 ajax 没有return,所以返回了undefined
2.现在的 ajax 返回了一个 promise 对象,这个promise对象可以对之前的异步请求添加成功和失败的回调
——类似jQuery返回一个 API 对象,这个对象可以操作之前的数据
3.总结: ajax() 返回了一个含有 .then 的对象
——如何返回对象:改源代码
4.2 修改源代码
- 使其返回一个含有 .then 的对象
- 在 ajax 函数一进来就 return
return new Promise((resolve, reject) => { })
1.new Promise:构造函数,接收的参数是一个函数
2.这个函数接收两个参数:resolve 和 reject
3.成功的时候调用:resolve
失败调用:reject - 这样就返回了一个 Promise的对象
ajax = (method, url, options) => {
return new Promise((resolve, reject) => {
const { succeess, fail } = options;
const request = new XMLHttpRequest();
request.open(method, url);
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status < 400) {
resolve.call(null, request.response);//this是null
} else if (request.status >= 400) {
reject.call(null, request);
}
}
};
request.send();
});
};
ajax('get','/xxx')
.then((response)=>{},(request)=>{})
4.3 背下这5个单词
return new Promise((resolve,reject)=>{})
5.小结
- 如何让异步的回调函数变成Promise函数
- 第一步
return new Promise((resolve,reject)=>{...})
- 任务成功则调用 resolve(result)
- 任务失败则调用 reject(error)
上面两个函数都只接受一个参数 - resolve和reject会再去调用成功和失败函数
resolve会调用then后面的第一个函数
reject会调用then后面的第二个函数
- 第二步
使用.then(success,fail)
传入成功和失败函数
6.现在封装的 ajax 的缺点
- post无法上传数据
request.send(这里可以上传数据,如用户名)
- 不能设置请求头
request.setRequestHeader(key,value)
- 解决办法:
1.花时间把 ajax 写到完美
2.使用 jQuery.ajax jQuery中文文档
—— jQuery.ajax 非常完美,但现在已经没有人用了
3.使用 axios (这个库比jQuery逼格高)
axios
- 目前最新的AJAX库
React和Vue都是用的这个 - 抄袭了jQuery的封装思路
- Axios 作弊表
- 通过博客快速了解axios的用法
1.axios的高级用法
- JSON自动处理
axios如果发现响应的 Content-Type 是json
就会自动调用 JSON.parse
正确设置Content-Type是一个好习惯 - 请求拦截器
可以在所有请求里加些东西,比如查询参数 - 响应拦截器
可以在所有响应里加些东西,甚至改内容 - 可以生成不同实例(对象)
不同的实例可以设置不同的配置,用于复杂常见
2.封装!
- 所有觉得麻烦的代码都封装起来!!!
3.Promise不能取消
- 但是axios可以取消,因为它自己有一个方式: aixos.CancelToken
- 但取消的不是promise,而是那个请求
总结
- 异步:不能直接拿到结果
- 异步为什么会用到回调?
为了拿到那个不能拿到的结果 - 回调的三个问题:回调地狱、名字、错误处理
- Promise是什么?
1976年的一种设计模式 - 如何使用Promise:五个单词
- 如何使用Axios:BootCDN中搜索axios,然后复制min.js 文件,复制scrpt标签即可
- Promise是前段解决异步问题的统一方案