为什么async异步函数尚未返回时,.then()语句就已提前执行?
问题核心原因
repeatAttempts虽然声明为async函数,但内部没有返回绑定重试结果的Promise,setInterval回调函数的返回值无法传递到外层函数,导致函数调用后立刻返回状态为已完成的Promise,值为undefined,这就是.then()先执行、拿不到执行结果的根本原因。- 外层的
try/catch无法捕获setInterval回调中抛出的错误,因为回调是异步调度执行的,运行时已经脱离了原try代码块的上下文。 - 现有逻辑不支持传入异步函数,如果传入的
func是异步函数,直接判断返回值会拿到Promise对象,永远判定为真值,会错误判定执行成功。
修复后的实现
推荐使用循环+延迟的写法,逻辑更清晰易维护:
const repeatAttempts = async (func, args, attempts, interval = 100) => { // 辅助延迟函数 const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)) for (let i = 0; i < attempts; i++) { const function_response = await func.apply(null, args) if (function_response) { console.log("function_response! = ", function_response); console.log("剩余尝试次数! = ", attempts - i - 1); return function_response } // 最后一次尝试失败不需要再延迟 if (i < attempts - 1) { await delay(interval) } } // 所有尝试都失败 throw new Error("Out of attempts") } const q = document.querySelector.bind(document) // 调用示例 repeatAttempts(q, ['dt'], 3) .then((c) => {console.log("then =",c)}) .catch(err => console.error(err))
配套测试HTML
<div> <dl> <dt><code>thisArg</code></dt> <dd> <p>调用<code>func</code>时指定的<code>this</code>值。</p> <p>注意该值不一定是方法实际接收到的this:如果方法是非严格模式下的函数,<code>null</code>和<code>undefined</code>会被替换为全局对象,原始值会被装箱。该参数为必填项。</p> </dd> <dt><code>argsArray</code> <span>可选</span></dt> <dd> <p>类数组对象,指定调用<code>func</code>时传入的参数,如果不需要给函数传参可以传<code>null</code>或<code>undefined</code>。</p> <p>从ECMAScript 5开始,这些参数可以是通用类数组对象,无需是数组。</p> </dd> </dl> </div>
修复后重试逻辑会等待执行结果,.then()可以正常拿到返回值,超出重试次数抛出的错误可以被.catch()捕获,同时兼容同步和异步传入函数。
内容的提问来源于stack exchange,提问作者beautysleep
相关产品推荐
相关产品推荐

