提出问题
使用 ajax 时,会遇到这种情况,需要先发 一个ajax请求,称之为 A请求,返回结果后,再发一个ajax请求,称之为 B请求。
也就是说这2个请求是有先后顺序的
问题:由于ajax是异步调用,也就是说无法确定这2个ajax的请求顺序
这里为了简单,通过 setTimeout() 模拟异步
setTimeout(function(){
console.log(111) // 虽然写在前面,但是后执行
},1000)
setTimeout(function(){
console.log(222) // 虽然写在后面,但是先执行
},500)
执行结果:
222
111
解决(正确但不推荐)
嵌套写法,将后面执行的 setTimeout() 放到 前面的 setTimeout 中:
setTimeout(function(){
console.log(111)
setTimeout(function(){
console.log(222)
},500)
},1000)
缺点:如果有多个 setTimeout,就需要多层嵌套,代码不清晰
Promise
Promise 类可以解决上面的问题,可以让异步程序,有顺序的执行
浏览器支持:由于 Promise 是 ES6 新增加的,所以一些旧的浏览器并不支持,苹果的 Safari 10 和 Windows 的 Edge 14 版本以上浏览器才开始支持 ES6 特性。
使用方法
new Promise(function (resolve, reject) {
// 异步代码
.......
// 表示执行成功,接下来会执行 then() 部分
// 此处的 a,传入 then() 中的 data
resolve(a)
// 表示执行失败,接下来会执行 catch() 部分
// 此处的 b,传入 catch() 中的 data
reject(b)
}).then(function(data){
// 代码块2
}).catch(function(data){
// 代码块3
})
需要向 Promise(f) 传入一个函数,该函数有2个参数,这2个参数也是函数
第一个是
resolve(data)(可以没有该代码块) ,调用该函数表示成功,接下来会执行then()中的回调函数。resolve(data)中的data传给then()函数第二个是
reject(data)(可以没有该代码块) ,调用该函数表示失败,接下来会执行catch()中的回调函数reject(data)中的data传给then()函数
案例1
实现本文开头两个 setTimeout() 同步写法,即:只需要处理 resolve(data) 成功情况
方式1-基础写法
适合简单功能
new Promise(function(resolve){
setTimeout(function(){
console.log(111)
resolve('AAA') // AAA会传给 then 中的 data
},1000)
})
.then(function(data){
setTimeout(function(){
console.log(222,data)
},500)
})
方式2-高级写法
封装成2个函数:
- 第一个函数返回
Promise对象 - 第二个函数获取到
Promise对象后,处理then部分
好处:这种方式在 ajax 中经常用到:
- 第一个函数封装发送
ajax请求,是公共函数,不再改变 - 第二个函数处理
ajax请求返回的结果,由用户自定义
function t(){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(111)
resolve('AAA') // AAA会传给 then 中的 data
},1000);
});
}
function my(){
t().then(function(data){
setTimeout(function(){
console.log(222,data)
},500)
})
}
my()
案例2
需要处理 resolve(data) 成功情况、reject(data) 失败情况
var successFlag = true
var pro = new Promise(function(resolve, reject){
setTimeout(function(){
console.log(111)
if (successFlag){
resolve("执行成功!")
}else{
reject("执行失败!")
}
},1000)
})
.then(function(data){
setTimeout(function(){
console.log(222,data)
},500)
}).catch(function(data){
setTimeout(function(){
console.log(333,data)
},500)
})
链式调用then(多个then写法)
then() 支持链式调用,即:支持多个 then() 顺序执行,此时 then() 方法要 返回 一个 Promise 对象
例子
有下面代码,3个函数中,每个函数都返回 Promise,该如何实现:先执行 t(),再实现 t2(),最后执行 t3()
function t(){
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(111)
resolve('AAA') // AAA会传给 then 中的 data
},1000);
});
}
function t2(){
return new Promise((resolve, reject) => {
setTimeout(function(){
console.log(222)
resolve('BBB')
},700)
});
}
function t3(){
return new Promise((resolve, reject) => {
setTimeout(function(){
console.log(333)
resolve('CCC')
},500)
});
}
错误执行方式
下面执行方式是无法保证顺序执行的:
t()
t2()
t3()
正确但不推荐的写法
下面方式执行正确,但又发生嵌套了,不推荐
t()
.then((val)=>{
console.log("t2-val:",val)
t2()
.then((val)=>{
console.log("t3-val:",val)
t3()
})
})
链式调用 then (推荐)
t()
.then((val)=>{
console.log("t2-val:",val)
return t2() // then中必须返回Promise
})
.then((val)=>{
console.log("t3-val:",val)
return t3() // 最后一个是否返回Promise无所谓
})
参考:
https://juejin.cn/post/6876686095954903048
https://juejin.cn/post/6948401178975666190