用四种方法将两个AJAX改为同步
Promise、Generator函数、yield、async/await 相关
今有一题,题目为:
- 现有
ajax1()
和ajax2()
,用于快速初始化CODE1和CODE2 - myFunc必须在CODE1和CODE2初始化之后再执行
- 可以在原代码上修改
伪代码为:
Ajax1({
...
success: function(data){
CODE1 = data
}
})
Ajax2({
...
success: function(data){
CODE2 = data
}
})
myFunc(CODE1, CODE2)
立Flag判断
作为一个后端,我最先想到的是创建一个变量来标志两个ajax是否完成,然后再两个ajax的回调中进行判断(至于两个ajax都改为同步这种方法直接不考虑),大致代码如下:
使用了setTimeOut
来模拟ajax:
let CODE1 = null
let CODE2 = null
function myFunc() {
console.log(CODE1, CODE2);
}
//第一种
let flag = 0 //flag默认为0
function ajax1() {
setTimeout(() => {
console.log('ajax1得到响应')
CODE1 = 'ajax1返回的数据'
//如果回调时flag为1,代表另一个ajax已经初始化成功
if (flag === 1) {
myFunc()
} else {
//否则flag+1代表本ajax成功
flag += 1
}
}, 1000)
}
function ajax2() {
setTimeout(() => {
console.log('ajax2得到响应')
CODE2 = 'ajax2返回的数据'
if (flag === 1) {
myFunc()
} else {
flag += 1
}
}, 2000)
}
ajax1()
ajax2()
执行结果:
可以看到myFunc在两个ajax执行完成之后才执行。
yield关键字
yield关键字是ES6添加的语法,可以在函数执行中交出运行权限
上面第一种方法一看就是不会前端的人写的,前端如果要想炫技的话可以这么写:
//第二种
//Promise执行器
function run(gen) {
gen = gen()
return next(gen.next())
function next({ done, value }) {
return new Promise(resolve => {
if (done) {
resolve(value)
} else {
value.then(data => {
next(gen.next(data)).then(resolve)
})
}
})
}
}
function ajax1() {
return new Promise(resolve => {
setTimeout(() => {
console.log('ajax1得到响应');
CODE1 = 'ajax1返回的数据'
resolve()
}, 5000)
})
}
function ajax2() {
return new Promise(resolve => {
setTimeout(() => {
console.log('ajax2得到响应');
CODE2 = 'ajax2返回的数据'
resolve()
}, 5000)
})
}
function* call() {
let aj1 = ajax1()
let aj2 = ajax2()
yield aj1
yield aj2
}
run(call).then(myFunc)
什么意思我解释不清楚,也不想解释,自己去看阮一峰的博客:Generator 函数的含义与用法
async/await关键字
async/await关键字是ES7的语法,是对上面Promise执行器的一种简化:
// 第三种
function ajax1() {
return new Promise(resolve => {
setTimeout(() => {
console.log('ajax1得到响应');
CODE1 = 'ajax1返回的数据'
resolve()
}, 1000)
})
}
function ajax2() {
return new Promise(resolve => {
setTimeout(() => {
console.log('ajax2得到响应');
CODE2 = 'ajax2返回的数据'
resolve()
}, 2000)
})
}
async function call() {
/*
这里不能这么写:
await ajax1()
await ajax2()
这样会在ajax1之后才会执行ajax2
需要写成下面的这种:
*/
let aj1 = ajax1()
let aj2 = ajax2()
await aj1
await aj2
myFunc()
}
call()
async声明这是一个内部存在同步的函数,只有声明了async,函数内部才能使用await,await代表等待Promise执行完毕才会继续执行,的确有点同步的感觉了。
Promise
上面用到了Promise但是都没介绍,就是想把最合适的一种放到最后:
//第四中,同时也是最优解
function ajax1(resolve, reject) {
setTimeout(()=>{
console.log('ajax1得到响应');
CODE1 = 'ajax1返回的数据'
resolve()
},1000)
}
function ajax2(resolve, reject) {
setTimeout(()=>{
console.log('ajax2得到响应');
CODE2 = 'ajax2返回的数据'
resolve()
},2000)
}
const p1 = new Promise(ajax1)
const p2 = new Promise(ajax2)
Promise.all([p1, p2]).then(myFunc)
函数Promise.all()
接收一个Promise数组参数,作用是数组内的Promise执行完毕之后会返回一个Promise对象。(还有一个Promise.race()
方法也挺好玩,作用是参数中任意一个Promise完成就返回一个Promise)