当异步任务有两个结果:成功和失败 时,怎么办?
方法一:回调接受两个参数
fs.readFile('./1.txt', (error, data) => {
if (error) {
console.log('失败');
return;
}
console.log(data.toString()); //成功
})
方法二:使用两个回调
ajax('GET', '/1.json', data() => {}, error() => {})
//data() => {} 是成功回调,error() => {} 是失败回调
//或者:
ajax('GET', '/1.json', {
success:()=>{}, fail:()=>{}
})
//接受一个对象,对象有两个key,表示成功和失败
这些方法的不足(这也是为什么使用 Promise 的原因):
- 名称不规范,有人用 success + error,有人用 success + fail,有人用 done + fail
- 容易出现回调地狱,代码变得看不懂
- 很难进行错误处理
解决回调问题(Promise 的用途):
- 规范回调的名字和顺序
- 避免回调地狱,让代码可读性更强
- 很方便地捕获错误
以 AJAX 的简单封装为例,未使用 Promise 前:
ajax = (method, url, options) => {
const {success, fail} = options //析构赋值
const request = new XMLHttpRequest()
request.open(method, url)
request.onreadystatechange = () => {
if (request.readyState === 4) {
//成功就调用 success,失败就调用 fail
if (request.status < 400) {
success.call(null, request.response)
} else if (request.status >= 400) {
fail.call(null, request, request.status)
}
}
}
request.send()
}
ajax('get', '/xxx', {
success(response) {}, fail: (request, status) => {}
})
//用到了两个回调,还使用了 success 和 fail
使用 Promise 的 AJAX 封装:
ajax = (method, url, options) => {
return new Promise((resolve, reject) => {
const request = new XMLHttpRequest()
request.open(method, url)
request.onreadystatechange = () => {
if (request.readyState === 4) {
//成功就调用 resolve,失败就调用 reject
if (request.status < 400) {
resolve.call(null, request.response)
} else if (request.status >= 400) {
reject.call(null, request)
}
}
}
request.send()
})
}
ajax('get', '/xxx')
.then((response) => {}, (request) => {})
//也是回调,但是不需要记 success 和 fail
//.then 的第一个参数就是 success
//.then 的第二个参数就是 fail
上面代码中,ajax() 返回了一个含有 .then() 方法的 Promise 对象。
使用 return new Promise((resolve, reject) => {...}) 就能得到这个含有 .then() 方法的对象。
总结
Promise 是前端解决异步问题的统一方案,Promise 的基本用法如下:
第一步: 定义
return new Promise((resolve, reject)=>{...})- 任务成功则调用 resolve(result)
- 任务失败则调用 reject(error)
- resolve 和 reject 会再去调用成功和失败函数
第二步:使用
使用 .then(success, fail) 传入成功和失败函数