qq_笑_17
回答:您可以使用Symbol.iterator根据for await来异步执行您的承诺。这可以打包成一个构造函数,在这个例子中它被调用Serial(因为我们正在一个一个地通过 promises,按顺序)function Serial(promises = []) { return { promises, resolved: [], addPromise: function(fn) { promises.push(fn); }, resolve: async function(cb = i => i, err = (e) => console.log("trace: Serial.resolve " + e)) { try { for await (let p of this[Symbol.iterator]()) {} return this.resolved.map(cb); } catch (e) { err(e); } }, [Symbol.iterator]: async function*() { this.resolved = []; for (let promise of this.promises) { let p = await promise().catch(e => console.log("trace: Serial[Symbol.iterator] ::" + e)); this.resolved.push(p); yield p; } } }}以上是什么?这是一个名为Serial.它将返回 Promise 的函数数组作为参数。函数存储在 Serial.promises它存储了一个空数组Serial.resolved- 这将存储已解决的承诺请求。它有两种方法:addPromise: 接受一个返回 Promise 的函数并将其添加到 Serial.promisesresolve:异步调用自定义Symbol.iterator. 这iterator会遍历每一个 promise,等待它完成,然后将它添加到Serial.resolved. 完成后,它返回一个映射函数,该函数作用于填充的Serial.resolved数组。这使您可以简单地调用resolve,然后提供对响应中成员的处理方式的回调。如果您将承诺返回给该函数,则可以传递一个then函数以获取整个数组。一个例子: promises.resolve((resolved_request) => { //do something with each resolved request return resolved_request; }).then((all_resolved_requests) => { // do something with all resolved requests });下面的例子展示了如何使用它来产生巨大的效果,无论你是希望在每个单独的分辨率上发生一些事情,还是等到一切都完成。请注意,它们将始终按顺序排列。这可以从第一个计时器设置为最高ms计数的事实中看出。第二个承诺不会甚至开始,直到第一个已完成,第三不会在第二饰面等之前开始这让我想到了一个重要的点。尽管按顺序序列化您的 Promise 是有效的,但重要的是要意识到,如果它们占用任何一个需要任何时间,这将延迟您对数据的响应。Parallel 的美妙之处在于,如果一切顺利,所有请求都需要更短的时间来完成。如果应用程序有多个必需的请求,那么像序列化这样的东西非常有用,如果一个请求不可用,或者一个项目依赖另一个(很常见),整个事情就会失败。//helpers let log = console.log.bind(console),promises = Serial(), timer = (tag, ms) => () => new Promise(res => { setTimeout(() => { res("finished " + tag);}, ms) });function Serial(promises = []) { return { promises, resolved: [], addPromise: function(fn) { promises.push(fn); }, resolve: async function(cb = i => i, err = (e) => console.log("trace: Serial.resolve " + e)) { try { for await (let p of this[Symbol.iterator]()) {} return this.resolved.map(cb); } catch (e) { err(e); } }, [Symbol.iterator]: async function*() { this.resolved = []; for (let promise of this.promises) { let p = await promise().catch(e => console.log("trace: Serial[Symbol.iterator] ::" + e)); this.resolved.push(p); yield p; } } }}promises.addPromise(timer(1, 3000));promises.addPromise(timer(2, 1000));promises.addPromise(timer(3, 2000));promises .resolve(msg => ( log(msg), msg) ) .then((complete) => log("everything is complete: " + complete));它是如何工作的?通过使用一个一个一个地调用每promise一个的迭代器,我们可以确定它们是按顺序接收的。虽然很多人没有意识到这一点Symbol.iterator是很多比标准更强大的for循环。这有两个重要原因。第一个原因,也是适用于这种情况的原因,是因为它允许异步调用会影响应用对象的状态。第二个原因是它可以用于提供来自同一对象的两种不同类型的数据。Ae 您可能有一个要读取其内容的数组:let arr = [1,2,3,4];您可以使用for循环或forEach获取数据:arr.forEach(v => console.log(v)); // 1, 2, 3, 4但是如果你调整迭代器:arr[Symbol.iterator] = function* () { yield* this.map(v => v+1);};你得到这个:arr.forEach(v => console.log(v));// 1, 2, 3, 4for(let v of arr) console.log(v);// 2, 3, 4, 5这对于许多不同的原因都很有用,包括时间戳请求/映射引用等。如果您想了解更多信息,请查看 ECMAScript 文档:For in 和 For Of 语句用:它可以通过使用返回 Promise 的函数数组调用构造函数来使用。您还可以通过使用向对象添加函数承诺new Serial([]).addPromise(() => fetch(url))在您使用该.resolve方法之前,它不会运行函数承诺。这意味着您可以在对异步调用执行任何操作之前,根据需要添加临时承诺。Ae 这两个是一样的:使用 addPromise: let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3)]); promises.addPromise(() => fetch(url4)); promises.resolve().then((responses) => responses)没有添加承诺: let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3), () => fetch(url4)]).resolve().then((responses) => responses)调整您的代码:以下是调整代码以按顺序执行操作的示例。问题是,您并没有真正提供大量的入门代码,因此我将您的scan函数替换为timer我在之前示例中使用的函数。要使用您的代码实现此功能,您所要做的就是从您的scan函数返回一个 Promise ,它会完美运行:)function Serial(promises = []) { return { promises, resolved: [], addPromise: function(fn) { promises.push(fn); }, resolve: async function(cb = i => i, err = (e) => console.log("trace: Serial.resolve " + e)) { try { for await (let p of this[Symbol.iterator]()) {} return this.resolved.map(cb); } catch (e) { err(e); } }, [Symbol.iterator]: async function*() { this.resolved = []; for (let promise of this.promises) { let p = await promise().catch(e => console.log("trace: Serial[Symbol.iterator] ::" + e)); this.resolved.push(p); yield p; } } }}const timer = (tag, ms) => new Promise(res => { setTimeout(() => { res("finished " + tag); }, ms)});function scanProducts() { return timer("products", 3000);}function scanCoupons() { return timer("coupons", 1000);}async function scanRetailers() { return timer("retailers", 2500);}function sendEmail(ses) { var email = { "Source": "test@gmail.com", "Template": "test-template", "Destination": { "ToAddresses": ["test@gmail.com"] }, "TemplateData": `{}` } ses.sendTemplatedEmail(email);}let promises = Serial([scanProducts, scanCoupons, scanRetailers]);promises.resolve().then(resolutions => console.log(resolutions));