用四種方法將兩個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)