typescript - for ループ内の配列を約束 - 2 回目の反復では空

okwaves2024-01-25  8

私は、Promise の配列に対して for ループを使用する正しい方法を理解しようと努めてきました。私のコードでは、配列に 3 つの要素がありますが、データがあるのはループの初回のみです。

  private populateRequest(connection: Connection, myArray: any[], containerId: string): Promise<void> {
    // tslint:disable-next-line:no-shadowed-variable
    return new Promise(async (resolve, reject) => {
      const promises: Array<Promise<SomeType>> = [];
      let status = '';

      // tslint:disable-next-line:prefer-for-of
      for (let i = 0; i < myArray.length; i++) {
        const data = await this.getResolvedPromise(myArray[i])
        .then(response => response)
        .catch(err => console.log(err));
        if (this.flags.hasOwnProperty('prop1')) {
          status = 'Active';
        } else if (this.flags.hasOwnProperty('prop2')) {
          status = 'Inactive';
        } else if (data[0]['WidgetProp1'] === 'Active') {
          status = 'Inactive';
        } else if (data[0]['WidgetProp1'] === 'Inactive') {
          status = 'Active';
        }

        const myMetaObj = {
          prop3: data[0]['WidgetProp3'],
          status
        };
        const myMetaMember = {
          ContainerId: containerId,
          ContentEntityId: data[0]['WidgetId'],
          Body: data[0]['WidgetBody'],
          Metadata: myMetaObj
        };

        promises.push(myMetaMember);
      }

      Promise.all(promises)
        .then(() => resolve())
        .catch(err => reject(err));
    });
  }

  private getResolvedPromise(target: Promise<any>): Promise<any> {
    // tslint:disable-next-line:no-any
    return new Promise((resolve, reject) => {
    // tslint:disable-next-line:no-any
    Promise.all([target])
     .then(() => resolve(target))
     .catch(err => reject(err));
    });
  }

プッシュは最初は意図したとおりに機能しますが、それ以降は機能しません。

これは非同期コードと呼び出しが完了していないことが原因であることは理解していますが、Promise.all() が正しく動作しない理由がわかりません。

ハルプス?

ここには多くの間違った点がありますが、これを書き直そうとするとき、トリガー配列に何が入っているのかを知る必要があります。そして、myArray 配列には何が入っているのでしょうか?そこにはどのような種類のデータが含まれていますか?そして、その配列から取得したデータに対して getResolvedPromise() を使って何をしようとしているのでしょうか?

– jfriend00

2020 年 9 月 4 日 23:09

triggers は myArray であるはずで、これには 3 つの解決された Promise が含まれています。これらにはすべて、コードの残りの部分で使用する必要がある約 5 つのプロパティがあります。このデータは最終的に SaaS API に送信されます。解決された約束しか得られません。なぜなら、約束を理解しようとして、解決できないと思ったからです。Promise オブジェクトを返す関数が必要でした。必要な 3 つはすでにあるので、解決された Promise の取得を破棄して、他のものと同様にプロパティによってオブジェクトにアクセスするだけでよいでしょうか?

– トレブルコード

2020 年 9 月 4 日 23:14

1

また、getResolvePromise() は何も役に立たないようです。 Promise.all([target]) を呼び出して、target に解決される Promise を返します。それは何も有益なことを達成していないようです。どう思いましたか帽子は達成していました。つまり、target があり、target を解決する Promise ができました。ターゲットが Promise だった場合でも、getResolvePromise() の呼び出し元は、その呼び出しから結果を取得するために await または .then() を使用する必要があります。

– jfriend00

2020 年 9 月 4 日 23:14

関数への入力が何であるか、必要な出力が何であるかをバックアップして説明してください。おそらくそれを実現する書き換えを示すことができます。現時点では、どのようなデータが入ってきて、どのようなデータを送り出したいのか、混乱していますか?

– jfriend00

2020 年 9 月 4 日 23:15

1

それでは、populateRequest() は何を返す、または何をするのでしょうか?

– jfriend00

2020 年 9 月 4 日 23:25



------------------------

ここにはいくつか間違った点があります。

まず、Promise 変数に Promise をプッシュしているわけではありません。 myMetaMember 変数をその配列にプッシュしています。

第 2 に、すでに await を使用して非同期リクエストをシリアル化している場合は、Promise.all() を使用する必要はまったくありません。

Tなるほど、必要がないときに手動で作成した Promise の追加レイヤーで既存の Promise をラップするという、いくつかのアンチパターンを使用しています。

第 4 に、通常、await と .then() および .catch() を混合したくないです。 await からのエラーをキャッチするには、try/catch を使用します。 await がすでに値を取得しているため、.then() は必要ありません。

第 5 に、getResolvePromise() は何も役に立たないようです。 Promise.all([target]) を呼び出して、target に解決される Promise を返します。それは何も有益なことを達成しているようには見えません。それによって何が達成されたと思いますか。

myArray が、それぞれの結果がオブジェクトになる Promise の配列であることが明らかになったので、ここでは、あなたがやろうとしていることについての私なりの最善の解釈を示します。

private populateRequest(connection: Connection, myArray: any[], containerId: string): Promise<Array<{ContainerId: string; ContentEntityId: unknown; Body: unknown; Metadata: {prop3: unknown; status: string}}>> {
      return Promise.all(myArray).then(results => {
          return results.map(data => {
              let status = '';
              if (this.flags.hasOwnProperty('prop1')) {
                status = 'Active';
              } else if (this.flags.hasOwnProperty('prop2')) {
                status = 'Inactive';
              } else if (data[0]['WidgetProp1'] === 'Active') {
                status = 'Inactive';
              } else if (data[0]['WidgetProp1'] === 'Inactive') {
                status = 'Active';
              }

              const myMetaObj = {
                prop3: data[0]['WidgetProp3'],
                status
              };
              const myMetaMember = {
                ContainerId: containerId,
                ContentEntityId: data[0]['WidgetId'],
                Body: data[0]['WidgetBody'],
                Metadata: myMetaObj
              };
              return myMetaMember;
          });
      });
  }

r を取得するにはmyArray からの結果 (それぞれがオブジェクトに解決される配列または Promise であると言った場合は、 Promise.all(myArray) を使用します。これにより、結果の配列に解決される単一の Promise が返され、それを使用できます。 ) 結果の配列を取得します。その後、その配列を反復して、データに基づいて新しいオブジェクトを構築できます。

追記myArray が実際に Promise の配列である場合は、それを myArray: any[] として宣言すべきではありません。これは、TypeScript が読者 (私) にそれが何であるかを教えず、正しいものが渡されることを TypeScript に強制させないという点で、TypeScript の理由の一部を無効にします。

2020 年 9 月 4 日 23:30 に回答

jfriend00

jfriend00

692,000

99

金バッジ 99 個

1002

銀バッジ 1002 個

銅バッジ 992 個

銅バッジ 992 個

5

@jfriend00、ありがとうございます。その説明は非常に明確です。これを回答としてマークします

– トレブルコード

2020 年 9 月 4 日 23:31

TypeScript に関しては、Promise<void> Promise<{…}[]> に変更する必要があります。メタメンバーのオブジェクト タイプを使用します。

– ベルギ

2020 年 9 月 4 日 23:34

@Bergi - TypeScript らしさを修正/改善するための編集を提案してください (または回答を自分で編集してください)。

– jfriend00

2020 年 9 月 4 日 23:36

@jfriend00 編集を提案する方法がわからない場合は、 [保存]をクリックすると、そのまま保存されます。

– ベルギ

2020 年 9 月 4 日 23:42

@Bergi - そうですね、あなたには編集のスーパーパワーがあるので、編集はそのまま適用されます。そうですね。

– jfriend00

2020 年 9 月 4 日 23:53



------------------------

あなたの例は本当に理解できません。でも私が見ているのは、あなたあなたは getResolvedPromise からの Promise を同期的に解決する await を使用しています。また、 .then を await と組み合わせて使用​​していますが、これは同じことを行うため意味がありませんが、「await」として別のスタイルで使用しているだけです。したがって、次のいずれかを実行します。

const data = await promise;
// data is resolved here

または

promise.then(
  data => // data is resolved here
)

.map を使用する代わりに for ループを使用して構造を反復する必要がある場合は、次のようなことを行うことをお勧めします。

async someFunction(): Promise<any[]> { 
  promises: Promise<any>[] = []
  for(const value of list) {
    promises.push(new Promise((resolve, reject) => {
      const data = await something
      // do something with data
      const fancyObject = {}
      resolve(fancyObject);

  }));
  return Promise.all(promises);
}

データ オブジェクトに依存するロジックは、await 演算子を介して Promise が解決された後にのみ実行されることがわかります。したがって、このロジックは Promise 自体でラップする必要があります。

Promise.all 自体は Promise を返すため、別の Promise でラップする必要はなく、すべての fancyObject を含む配列に解決されます。 await 構文には try catch ブロックが必要であることにも注意してください。Promise の解決中に発生するエラーを捕捉するため。

私があなたの話を正しく理解し、私の例を何かに応用できることを願っています。

6

はい、これは理にかなっています。@leonat に感謝します。考えてみるととても楽しかったです。

– トレブルコード

2020 年 9 月 4 日 23:23

私たちはここにいるのでここでの実際のデータと関数が何を行うべきかを理解するには、OP と積極的に連携する必要があります。問題の一部についてコメントを提供するよりも、それが明確になるまで待った方がよいでしょう。また、OP に明確な質問を書いてもらい、明確な回答を書けるように努めています (これにより、StackOverflow がより便利な場所になります)。

– jfriend00

2020 年 9 月 4 日 23:24

問題は、await と .then() をよりよく理解する必要があることと、まったく必要のない機能です。

– トレブルコード

2020 年 9 月 4 日 23:27

私が回答を書いたとき、あなたのコメントは存在しませんでした。 stackoverflow 応答を扱うのはこれが初めてなので、応答プロセスがどのように機能するかを理解する必要があります。答える前に質問を明確にすることは理にかなっています。次回はそうします。それでも私は、全体の混乱は、Promise がどのように機能するかについての誤解から生じたと思います。そのため、for ループで Promise を操作する方法についての最低限のテンプレートを提供しました。

– レオナット

2020 年 9 月 4 日 23:29

問題ありません。あなたはただ助けようとしただけのようですね (それは良いことです)。

– jfriend00

2020 年 9 月 4 日 23:33

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。