英文:
recursive function with a promise to iterative
问题
我有一个名为emailIterator
的函数,它从一个stack
中读取messages
,然后逐个使用emailer
发送它们。
我目前是通过递归处理它,每次都使用相同的messages
再次调用emailIterator
,但每次都减少一个消息,因为它已经发送过了。
import { emailer } from 'pigeon';
interface MessageObject {
email: string;
recipientName: string;
message: string;
}
interface ErrorFormat {
error: any;
messageAtError: MessageObject;
}
const data: MessageObject[] = [
{
email: 'bob@domain.com',
recipientName: 'Bob',
message: 'Lorem ipsum dolor sit amet mattis.',
},
{
email: 'jim@domain.com',
recipientName: 'Jim',
message: 'Lorem ipsum dolor sit amet mattis.',
},
];
const emailIterator = (messages: MessageObject[], cb: any): void => {
if (messages.length === 0) {
return cb(undefined, 'All messages sent');
} else {
const toSend = messages.pop();
emailer(toSend)
.then(() => {
return emailIterator(messages, cb);
})
.catch((e) => {
return cb({
error: e,
messageAtError: toSend,
});
});
}
};
emailIterator(data, (err?: ErrorFormat, msg?: string) => {
if (err) {
console.log('There was an error with a message:', err.messageAtError);
console.error(err.error);
return;
}
console.log(msg);
});
我需要帮助将这个转变为一个迭代的解决方案。
以下是我迄今为止想到的,这样做对吗?它是否有效地处理了错误?是否有更好的方法?
const emailIterator2 = async (messages: MessageObject[], cb: any): Promise<void> => {
for (let i = messages.length - 1; i >= 0; i--) {
let toSend = messages[i];
try {
const result = await emailer(toSend);
} catch (e) {
return cb({
error: e,
messageAtError: toSend,
});
}
if (i === 0) {
return cb(undefined, 'All messages sent');
}
}
}
英文:
I have a function emailIterator
which reads messages
from a stack
and sends them one by one using an emailer
I'm currently handling it recursively by calling emailIterator
back with the same messages
but only with one less message each time since it already got sent.
import { emailer } from 'pigeon';
interface MessageObject {
email: string;
recipientName: string;
message: string;
}
interface {
error: any;
messageAtError: MessageObject;
}
const data: MessageObject[] = [
{
email: 'bob@domain.com',
recipientName: 'Bob',
message: 'Lorem ipsum dolor sit amet mattis.',
},
{
email: 'jim@domain.com',
recipientName: 'Jim',
message: 'Lorem ipsum dolor sit amet mattis.',
},
];
const emailIterator = (messages: MessageObject[], cb: any): void => {
if (messages.length === 0) {
return cb(undefined, 'All messages sent');
} else {
const toSend = messages.pop();
emailer(toSend)
.then(() => {
return emailIterator(messages, cb);
})
.catch((e) => {
return cb({
error: e,
messageAtError: toSend,
});
});
}
};
emailIterator(data, (err?: ErrorFormat, msg?: string) => {
if (err) {
console.log('There was an error with a message:', err.messageAtError);
console.error(err.error);
return;
}
console.log(msg);
});
I need help to transform this into an iterative solution.
here's what I came up with so far, is this right? does it handle errors efficiently? can it be done in a better way ?
const emailIterator2 = (messages: MessageObject[], cb: any): void => {
for(let i = messages.length - 1; i >= 0; i--) {
let toSend = messages[i];
try {
const result = await emailer(toSend);
} catch (e: ErrorFormat) {
return cb({
error: e,
messageAtError: toSend
})
}
if(i === 0) {
return cb(undefined, 'All messages sent')
}
}
}
答案1
得分: 1
在 for..of
循环内使用 async..await
-
const emailIterator = async (messages: MessageObject[], cb: any): void => {
let toSend
try {
for (const m of messages) {
toSend = m
await emailer(m)
}
cb(undefined, "All messages sent")
}
catch (e) {
cb({ error: e, messageAtError: toSend })
}
}
将回调与 promises 混合使用的体验不佳。怎么样将 emailIterator
设计为基于 promises 的函数呢?
const emailIterator = async (messages: MessageObject[]): Promise<string> => {
let toSend
try {
for (const m of messages) {
toSend = m
await emailer(m)
}
return "All messages sent";
}
catch (e) {
e.messageAtError = toSend;
throw e;
}
}
注意奇怪的 toSend
赋值,以便在 catch
块中使用?更好的方式是让 emailer
抛出适当的错误 -
async function emailer(message): Promise<void> {
try {
// ...
}
catch (e) {
e.messageAtError(message);
throw e;
}
}
emailIterator
现在不需要担心它。行为相同,无需使用 try..catch
,错误会按预期冒泡。哦,而 TypeScript 也可以轻松推断出返回类型为 Promise<string>
-
async function emailIterator(messages: MessageObject[]) {
for (const m of messages)
await emailer(m);
return "All messages sent";
}
英文:
Use async..await
inside a for..of
loop -
const emailIterator = async (messages: MessageObject[], cb: any): void => {
let toSend
try {
for (const m of messages) {
toSend = m
await emailer(m)
}
cb(undefined, "All messages sent")
}
catch (e) {
cb({ error: e, messageAtError: toSend })
}
}
Mixing callbacks with promises has bad ergonomics. How about making emailIterator
a promise-based function?
const emailIterator = async (messages: MessageObject[]): Promise<string> => {
let toSend
try {
for (const m of messages) {
toSend = m
await emailer(m)
}
return "All messages sent"
}
catch (e) {
e.messageAtError = toSend
throw e
}
}
Notice the odd toSend
assignment so it can be used in the catch
block? Better yet is to have emailer
throw the proper error -
async function emailer(message): Promise<void> {
try {
// ...
}
catch (e) {
e.messageAtError(message)
throw e
}
}
emailIterator
doesn't have to worry about it now. Behaviour is the same, no try..catch
is needed and errors bubble up as expected. Oh and TypeScript can easily infer the Promise<string>
return type too -
async function emailIterator(messages: MessageObject[]) {
for (const m of messages)
await emailer(m)
return "All messages sent"
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论