求解惑:连续点击下面的按钮,触发异步请求,下面三种方法处理,为什么使用方法三之后,不能得到正确的值
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button onclick="fn()">点击我</button>
<input type="text" id="inp">
</body>
<script>
const query = () => {
return new Promise((succ, fail) => {
setTimeout(() => {
succ(1)
}, 1000);
})
}
let cont = 1
let fn = async () => {
//方法一:可以
// query().then(res => {
// cont += res
// inp.value = cont
// })
//方法二:可以
// let num = await query()
// cont += num
//方法三:不行,求解答
cont += await query()
inp.value = cont
}
</script>
</html>
参考GPT和自己的思路:
方法三无法得到正确的值的原因是因为在async函数内部调用了await关键字,它会使得函数内部的代码被挂起,并等待Promise对象的结果,然而在此代码中,每次点击按钮都会生成一个新的Promise对象,在第二个Promise对象完成之前,第一个Promise对象并没有完成,所以在第一个Promise对象完成之后,cont以前的值已经被累加了两次,导致了结果的错误。更改方法可以使用async和await组合操作或者生成执行上下文环境。
该回答引用GPTᴼᴾᴱᴺᴬᴵ
在方法三中,cont += await query()会先执行异步操作query()并返回一个Promise对象,然后将该Promise对象的resolve值加到cont上。但是在执行异步操作期间,下一行代码inp.value = cont已经开始执行了,此时cont的值还没有被更新。因此,在执行inp.value = cont时,cont的值仍然是1,而不是2。这就是为什么方法三不能得到正确的值的原因。
·
要解决这个问题,可以将异步操作和后续的代码分别放在两个then()回调函数中,以确保异步操作完成后再执行后续代码。例如,可以将方法三改写为:
let fn = () => {
query().then(res => {
cont += res
}).then(() => {
inp.value = cont
})
}
这样就能保证异步操作完成后,cont的值已经被正确更新,然后再将更新后的值赋给inp.value。