3 回答
![?](http://img1.sycdn.imooc.com/54584d9f0001043b02200220-100-100.jpg)
TA贡献1111条经验 获得超0个赞
我将转换dynamoClient.scan为基于 Promise 的函数,然后await每次调用它,例如:
const dynamoClientScanProm = (params) => new Promise((resolve, reject) => {
dynamoClient.scan(params, function (err, data) {
if (err) reject(err);
else resolve(data);
});
});
// ...
// in an async function:
try {
await dynamoClientScanProm(productParams);
await dynamoClientScanProm(couponsParams);
await dynamoClientScanProm(retailerParams);
// promisify/await this too, if it's asynchronous
ses.sendTemplatedEmail(email);
} catch(e) {
// handle errors
}
目前还不清楚是否需要使用调用的结果,但是如果确实需要结果并且不只是需要等待 Promise 解析,则在awaiting时赋值给一个变量,例如
const productResults = await dynamoClientScanProm(productParams);
也就是说,如果 的其他调用没有使用结果dynamoClientScanProm,那么并行(使用Promise.all)而不是串行运行所有调用会更有意义,这样可以更快地完成整个过程。
![?](http://img1.sycdn.imooc.com/5859e2d50001f6bb01000100-100-100.jpg)
TA贡献1818条经验 获得超7个赞
回答:
您可以使用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.promises
resolve
:异步调用自定义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, 4
for(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));
![?](http://img1.sycdn.imooc.com/5458477300014deb02200220-100-100.jpg)
TA贡献1779条经验 获得超6个赞
使用异步系列。它按顺序运行一系列回调,尽可能简单。
series([
function(done) {
console.log('first thing')
done()
},
function(done) {
console.log('second thing')
done(new Error('another thing'))
},
function(done) {
// never happens, because "second thing"
// passed an error to the done() callback
}
], function(err) {
console.log(err.message) // "another thing"
})
添加回答
举报