如何让函数等待已存在的Promise完成?双按钮交互场景实现
问题
我开发的应用包含两个提交按钮:第一个按钮通过Promise发起需耗时数秒的API调用;第二个按钮收集用户输入后,需结合该API请求的输出进行处理。我希望实现以下流程:先启动API请求,用户完成选择后,点击第二个按钮时等待初始请求完成再执行后续逻辑。
相关代码如下:
this.upload.addEventListener('change', (event) => { .... // initial submit button API.getHumanFaceLandmarks(data.corrected).then((landmarks) => { console.log(landmarks); this.humanFeatures = extractHumanFeatures.beginRender( landmarks, data.canvas, this.EYE_MASK, this.MOUTH_MASK, this.EYE_SELECTOR, this.MOUTH_SELECTOR); }).catch(error => console.log('error', error)); }); pet.addEventListener('click', (event) => { // second submit renderPetswitch.outputFinalImage( event.target.dataset.name, this.humanFeatures, // <--- 如何等待这个值解析完成后再执行函数? this.OUTPUT_CANVAS); })
API方法实现:
getHumanFaceLandmarks: async function(data) { console.log(data.substring(0, 50) + '...'); const headers = new Headers(); headers.append("Content-Type", "application/json"); const body = JSON.stringify({ "image": data }); const requestOptions = { method: 'POST', headers: headers, body: body, redirect: 'follow' }; const response = await fetch(constants.HUMAN_FACE_LANDMARKS_ENDPOINT, requestOptions); return response.json(); }
请问在用户提交第二步操作时,如何让函数等待已存在的Promise完成?我希望优化用户体验,因此不想一次性完成所有请求。
解决方案
核心思路是保存第一个API请求返回的Promise对象,而非直接等待它完成后赋值。这样用户点击第二个按钮时,就能直接等待这个已存在的Promise——不管它已经完成还是正在执行。
步骤1:保存API请求的Promise链
修改第一个按钮的事件处理代码,把包含后续渲染逻辑的整个Promise链保存为实例变量:
this.upload.addEventListener('change', (event) => { .... // 保存完整的Promise链,让Promise最终解析为处理后的humanFeatures this.humanFeaturesPromise = API.getHumanFaceLandmarks(data.corrected) .then((landmarks) => { console.log(landmarks); return extractHumanFeatures.beginRender( landmarks, data.canvas, this.EYE_MASK, this.MOUTH_MASK, this.EYE_SELECTOR, this.MOUTH_SELECTOR ); }) .catch(error => { console.log('error', error); // 抛出错误,让后续调用能捕获到异常 throw error; }); });
步骤2:在第二个按钮中等待Promise完成
修改第二个按钮的点击事件,用async/await等待Promise完成后再执行后续逻辑:
pet.addEventListener('click', async (event) => { // 先判断是否存在有效请求,避免用户未执行第一步就点击第二步 if (!this.humanFeaturesPromise) { console.log('请先完成第一步操作'); return; } try { // 等待Promise完成,获取最终的humanFeatures const humanFeatures = await this.humanFeaturesPromise; // 执行最终渲染逻辑 renderPetswitch.outputFinalImage( event.target.dataset.name, humanFeatures, this.OUTPUT_CANVAS ); } catch (error) { console.log('处理失败:', error); } });
额外优化:避免重复发起请求
如果用户多次点击第一个按钮,可以在赋值前判断Promise是否已存在,避免重复请求:
this.upload.addEventListener('change', (event) => { .... // 若已有未完成的请求,直接返回 if (this.humanFeaturesPromise) { console.log('请求正在处理中,请稍后'); return; } this.humanFeaturesPromise = API.getHumanFaceLandmarks(data.corrected) .then((landmarks) => { console.log(landmarks); return extractHumanFeatures.beginRender( landmarks, data.canvas, this.EYE_MASK, this.MOUTH_MASK, this.EYE_SELECTOR, this.MOUTH_SELECTOR ); }) .catch(error => { console.log('error', error); throw error; }) // 请求完成后清空Promise,允许下次重新发起 .finally(() => { this.humanFeaturesPromise = null; }); });
这种方式既实现了“先启动API请求,用户选完后等待请求完成再执行第二步”的流程,还优化了重复点击的问题,完全匹配你的用户体验需求。
内容的提问来源于stack exchange,提问作者dave
相关产品推荐
相关产品推荐

