首页
关于
Search
1
如何使用img标签和picture标签的srcset/sizes属性
307 阅读
2
ES6 更新内容简介
282 阅读
3
使用Git进行版本控制
216 阅读
4
CSS动画实现
203 阅读
5
vue3之Composition API
175 阅读
WEB前端
CSS
VUE
HTML
小记
登录
Search
标签搜索
游戏
JavaScript
异步
动画
Shthah
累计撰写
36
篇文章
累计收到
59
条评论
首页
栏目
WEB前端
CSS
VUE
HTML
小记
页面
关于
搜索到
1
篇与
的结果
2023-03-09
Promise.all
promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果。promise.all中只要有一个失败了,走.catch(),在.catch()中获取第一个失败请求rejected抛出的结果。在 Promise.all 中,如果其中任何一个 Promise 被 rejected 或抛出异常,则整个 Promise.all 将会立即被 reject,而不会等到其他 Promise 完成。具体地说,一旦一个 Promise 失败,Promise.all 就会中止并返回一个新的拒绝状态的 Promise。然后**,其他未完成的 Promise 将会继续运行,但是它们的结果将会被忽略,不会进一步处理。等待多个 Promise创建一些模拟任务并逐一等待它们:const tasks = [ { id: 'A', durationMs: 2000, fulfills: true }, { id: 'B', durationMs: 3000, fulfills: true }, { id: 'C', durationMs: 1000, fulfills: true }, ]; try { for (const task of tasks) { await doTask(task); } console.log('success'); } catch (e) { console.log('failure'); }输出:Promise A: fulfilled ✅约 2 秒后 ( t=2)。Promise B: fulfilled ✅约 3 秒后 ( t=5)。Promise C: fulfilled ✅约 1 秒后 ( t=6)。这段代码可以运行,但速度很慢,因为它在循环的每次迭代中一次构造一个 Promise for-of,因此未来的 Promise 只有在之前的 Promise 都已实现后才会构造。如果第一个 Promise 需要很长时间才能实现,但未来的 Promise 需要的时间较少,我们最终会浪费时间,因为我们本可以安排那些更快的 Promise 回调更早运行。事实上,在实际实现中,doTask可能会向服务器发出网络请求。使用我们当前的方法,这意味着我们一次发出一个网络请求,这不必要地慢,因为浏览器支持并发网络请求。同步构建 Promise提前构建所有 Promise 然后等待它们会更有效率。这样,如果 Promise 执行器函数发出网络请求,这些请求可以由运行时并发处理。const tasks = [ { id: 'A', durationMs: 2000, fulfills: true }, { id: 'B', durationMs: 3000, fulfills: true }, { id: 'C', durationMs: 1000, fulfills: true }, ]; try { const promises = tasks.map((task) => doTask(task)); for (const promise of promises) { await promise; } console.log('success'); } catch (e) { console.log('failure'); }在此示例中,我们将每个任务映射到 的结果doTask,该结果返回一个 Promise。因此,我们得到了一个待定 Promises 数组:[Promise {<pending>}, ..., Promise {<pending>}]这一次,如果doTask浏览器发出网络请求,它可以发出多个并发请求,因为我们提前构造了所有 Promises。我们仍然会按照构造顺序一次等待一个 Promises,但不同之处在于其他网络请求可以在后台处理,而无需我们等待。如果任何单个 Promise 拒绝,上述代码实际上会抛出未捕获的错误解决方案:Promise.allPromise.all接受一个 Promise 的可迭代对象并返回一个新的外部 Promise,一旦所有单个 Promise 都已实现,该外部 Promise 便会实现,而一旦单个 Promise 拒绝,该外部 Promise 便会拒绝。此外,如果Promise.all实现,它会使用所有单个已实现值的数组来实现。try { const values = await Promise.all([p1, p2, ..., pn]); console.log('All promises fulfilled', values); } catch (e) { console.log('A promise rejected'); }Promise.all这比一次等待一个 Promises 更快,因为在调用时 Promises 已经构造好了。const tasks = [ { id: 'A', durationMs: 2000, fulfills: true }, { id: 'B', durationMs: 3000, fulfills: true }, { id: 'C', durationMs: 1000, fulfills: true }, ]; try { await Promise.all(tasks.map((task) => doTask(task))); console.log('Promise.all fulfilled'); } catch (e) { console.log('Promise.all rejected'); }如果 Promise 执行器函数doTask发起网络请求,我们可以看到性能的大幅提升,因为一旦构建了 Promise,浏览器就会同时执行这些网络请求。相比之下,在我们的第一个for-of循环方法中,我们必须在循环的每次迭代中一次发出一个网络请求。如果第一个请求需要很长时间才能解决,那么后续可能在很长一段时间内都不会被创建。但是,不要误Promise.all以为这是真正的并行;Promise回调仍会在事件循环中一次排队一个,并且永远不会同时运行。队列总是一次弹出一个项目,事件循环每次只运行一件事。失败状态const tasks = [ { id: 'A', durationMs: 2000, fulfills: true }, { id: 'B', durationMs: 3000, fulfills: true }, { id: 'C', durationMs: 1000, fulfills: false }, // rejects ]; try { await Promise.all(tasks.map((task) => doTask(task))); console.log('Promise.all fulfilled'); } catch (e) { console.log('Promise.all rejected'); } Promise C: rejected ❌ Promise.all rejected Promise A: fulfilled ✅ Promise B: fulfilled ✅请注意 Promise C 会提前拒绝,因为我们不会等待其他 Promise 解决后再构造并等待它。但更重要的是,Promise.all根据规范,Promise C 拒绝后会立即拒绝。这很棒,因为这意味着我们不必等待其余 Promise 解决 - 只要一个 Promise 拒绝,我们就可以立即开始处理错误情况。此行为称为快速失败。Promise.all不会立即取消Promise.all剩余的待处理 Promise。因此,剩余的 Promise 回调仍然会在事件循环中排队,并在轮到它们时运行。因此,即使在 Promise C 被拒绝后被拒绝,Promise A 和 B 仍然有机会解决。只是我们不必等待其他Promise 解决后再拒绝外部 Promise,这使我们能够更快地处理拒绝。如果 Promise A 或 Promise B 在被拒绝后又被拒绝,会发生什么情况Promise.all?从技术上讲,它们只会拒绝Promise.all已经被拒绝的 Promise。而拒绝已解决的 Promise 不会产生任何效果。
2023年03月09日
122 阅读
0 评论
0 点赞