JavaScript:如何确保所有Promise处于已敲定状态?代码正确性咨询
问题分析与解决方案
你的代码核心问题
你写的while (!finishWaiting)是同步死循环,会完全阻塞JavaScript的事件循环。因为JS是单线程的,同步代码执行时,微任务队列(比如Promise的then回调)根本没有机会被处理。也就是说allPromises.then里的finishWaiting = true永远不会执行,代码会一直卡在这个循环里,页面直接卡死。
正确实现方式
你需要利用Promise的异步特性等待所有结果,而非用同步循环阻塞线程。以下分两种场景给出方案:
方案一:改为async/await函数(最简洁推荐)
如果允许把函数改成async函数,代码会非常直观:
async function yourFunction() { let promisesToWait = []; // 存储所有结果的数组 let results = []; for (let constraintIndex = 0; constraintIndex < constraintsArray.length; constraintIndex++) { let curConstraints = constraintsArray[constraintIndex]; let curPromise = navigator.mediaDevices.getUserMedia(curConstraints) .then(stream => { // 处理resolve逻辑 return { status: 'fulfilled', value: stream }; }) .catch(err => { // 处理reject逻辑 return { status: 'rejected', reason: err }; }); promisesToWait.push(curPromise); } // 等待所有Promise敲定 let allResults = await Promise.allSettled(promisesToWait); // 对应你代码的C点,在这里处理所有结果 allResults.forEach(result => { if (result.status === 'fulfilled') { // 处理成功的stream console.log('成功获取流:', result.value); } else { // 处理失败的情况 console.log('获取流失败:', result.reason); } }); // 可在此return结果,函数会返回一个Promise return allResults; }
方案二:保持非async函数,用Promise回调处理后续逻辑
如果必须保持函数是非async的,所有需要在Promise敲定后执行的逻辑(结果收集、return相关处理)都要放到Promise.allSettled的then回调里:
function yourFunction() { let promisesToWait = []; for (let constraintIndex = 0; constraintIndex < constraintsArray.length; constraintIndex++) { let curConstraints = constraintsArray[constraintIndex]; let curPromise = navigator.mediaDevices.getUserMedia(curConstraints); promisesToWait.push(curPromise); } // 等待所有Promise敲定后处理结果 Promise.allSettled(promisesToWait).then(allResults => { // 对应你代码的C点,在这里处理所有结果 allResults.forEach(result => { if (result.status === 'fulfilled') { // 处理成功的stream console.log('成功获取流:', result.value); } else { // 处理失败的情况 console.log('获取流失败:', result.reason); } }); // 如果需要向外部传递结果,可使用回调函数 // 例如:callback(allResults); }); // 非async函数在此return无法返回Promise结果,只能提前返回 // 若需获取结果,必须通过回调或让函数返回Promise(本质和async函数一致) }
补充说明
- 你之前在每个
curPromise上单独绑定then和catch是可行的,但用Promise.allSettled统一收集所有结果会更高效,它会返回所有Promise的敲定状态(成功/失败)。 - 永远不要用同步循环等待异步操作,这会彻底阻塞JS线程,导致页面无响应。异步操作的等待必须用Promise的
then或await实现。
内容的提问来源于stack exchange,提问作者user19309573
相关产品推荐
相关产品推荐

