JS嵌套ajax+setInterval,怎样改成同步请求?
怎样让下面这段代码变成同步,顺序的打印出1 0 0 0 2 0 0 0 3 0 0 0 4 5
func() { console.log(1)
const arr = [2, 3, 4]
arr.forEach((num, idx) => {
this.$http.get('a-url').then(() => {
const interval = setInterval(() => {
let i = 0
this.$http.get('b-url').then(() => {
i = i + 1
console.log(0)
if(i === 3) {
clearInterval(interval)
}
})
}, 1000)
})
console.log(num)
})
console.log(5)
}
回答:
async func() { console.log(1)
const arr = [5, 6, 7]
for (const num of arr) {
await this.$http.get("a-url");
let i = 1;
await new Promise((resolve, reject)=>{
const interval = setInterval(async () => {
i = i + 1
await this.$http.get("b-url")
num<6&&console.log(i)
if(i === 4) {
clearInterval(interval)
resolve()
}
}, 1000)
})
console.log(num)
}
console.log(8)
}
回答:
新问题就简单很多了,但是因为是使用 forEach()
所以就不能直接使用 async/await 了,得使用 Promise
来配合,但是代码会比较复杂,所以如果可以改成 for
循环的话,就可以使用 async/await
了,代码会精简很多:
async function fn(){ console.log(1)
const arr = [2, 3, 4]
for(const num of arr){
// 等待A请求完成
await getAction('a-url')
// 等待B请求完成,并输出 3 次 0
await new Promise((resolve) => {
let i = 0 // 题目中声明的位置错误会造成死循环,所以调整了位置
const interval = setInterval(() => {
getAction('b-url').then(() => {
i = i + 1
console.log(0)
if(i === 3) {
clearInterval(interval)
resolve() // 完成 Promise
}
})
}, 1000)
})
console.log(num)
}
console.log(5)
}
fn()
// 假请求函数
function getAction(url){
return new Promise((resolve) => {
setTimeout(() => { resolve() }, 300)
})
}
正常业务场景里面是不会遇到这样的情况的,所以基本就是面试题,而且还是专门来为难面试者的了。
因为中间输出的 2
,3
,4
是重复输出,在浏览器控制台看似时输出了 2 3 4
但其实是合并后的,也就是输出的 2 2 2 3 3 3 4 4 4
。
所以不能简单使用 async/await
来同步执行,所以依旧使用 Promise
来实现。
魔改了代码,以便可以直接在浏览器控制台输出:
function fn(){ console.log(1)
const arr = [5, 6, 7]
// 需要异步全部执行完毕之后输出 8 ,所以需要使用到 `Promise.all`
Promise.all(arr.map(num => {
return new Promise((resolve1) => {
getAction('a-url').then(() => {
// 中间输出的 2,3,4 是重复输出,也就是输出的 2,2,2,3,3,3,4,4,4
// 所以不能简单使用 `async/await` 来同步执行,所以依旧使用 `Promise`
const tmp = () => {
return new Promise((resolve2) => {
// 正常 A 请求完毕之后业务代码
let i = 1;
const interval = setInterval(() => {
i = i + 1
getAction('b-url').then(() => {
console.log(i)
if(i === 4) {
clearInterval(interval)
// 这里是个坑,直接 resolve 会有微任务插队的问题
setTimeout(() => resolve2(),0)
}
})
}, 1000)
})
}
// 2,2,2,3,3,3,4,4,4 输出完毕之后输出 num
tmp().then(() => {
console.log(num)
resolve2()
})
})
})
})).then(() => {
// 全部输出完毕后输出 8
console.log(8)
})
}
fn()
// 假请求函数
function getAction(url){
return new Promise((resolve) => {
// 异步事件不能过长,不然会超过 B 请求时 1000ms 的定时器,输出顺序会错位。
setTimeout(() => { resolve() }, 200)
})
}
以上是 JS嵌套ajax+setInterval,怎样改成同步请求? 的全部内容, 来源链接: utcz.com/p/933573.html