递归函数与承诺(Promise)转化为迭代。

huangapple go评论64阅读模式
英文:

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 &#39;pigeon&#39;;
 
interface MessageObject {
  email: string;
  recipientName: string;
  message: string;
}
 
interface  {
  error: any;
  messageAtError: MessageObject;
}
 
const data: MessageObject[] = [

  {
    email: &#39;bob@domain.com&#39;,
    recipientName: &#39;Bob&#39;,
    message: &#39;Lorem ipsum dolor sit amet mattis.&#39;,
  },
  {
    email: &#39;jim@domain.com&#39;,
    recipientName: &#39;Jim&#39;,
    message: &#39;Lorem ipsum dolor sit amet mattis.&#39;,
  },
];
 
const emailIterator = (messages: MessageObject[], cb: any): void =&gt; {
  if (messages.length === 0) {
    return cb(undefined, &#39;All messages sent&#39;);
  } else {
    const toSend = messages.pop();
 
    emailer(toSend)
      .then(() =&gt; {
        return emailIterator(messages, cb);
      })
      .catch((e) =&gt; {
        return cb({
          error: e,
          messageAtError: toSend,
        });
      });
  }
};



 
emailIterator(data, (err?: ErrorFormat, msg?: string) =&gt; {
  if (err) {
    console.log(&#39;There was an error with a message:&#39;, 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 =&gt; {
	for(let i = messages.length - 1; i &gt;= 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, &#39;All messages sent&#39;)
    }
  }
}

答案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 =&gt; {
  let toSend
  try {
    for (const m of messages) {
      toSend = m
      await emailer(m)
    }
    cb(undefined, &quot;All messages sent&quot;)
  }
  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&lt;string&gt; =&gt; {
  let toSend
  try {
    for (const m of messages) {
      toSend = m
      await emailer(m)
    }
    return &quot;All messages sent&quot;
  }
  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&lt;void&gt; {
  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&lt;string&gt; return type too -

async function emailIterator(messages: MessageObject[]) {
  for (const m of messages)
    await emailer(m)
  return &quot;All messages sent&quot;
}

huangapple
  • 本文由 发表于 2023年2月27日 07:25:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75575626.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定