Promiseとasync、待機


TFTトラヒック検索サイトを作成してAPIを要求する場合,promissitionはほぼ強制的に使用される.でも思ったほどうまくいかなかった
Promise、async、awaitなどの非同期サポート関数が以前に位置決めされていたことは明らかです.しかし、海門の意味は完全に理解されていない.また,この項目はTypeScriptも併用しているため,混同しやすい.
今は私の考え通りに運用できるようになったので、書きます.

1.Promiseが登場する前に


まず、非同期機について簡単に説明します.
ここにJSの代表的な非同期関数settimeoutがあります.Cherryを0.5秒後に出力し、Melonを出力したい.
setTimeout(() => {
  console.log("Cherry");
}, 500);

console.log("Melon");

しかし結果はMELON出力,0.5秒後にCherry出力となる.このように、特定のコードの実行が完了するのを待たずに、次のコードを実行することは非同期処理である.
次に、非同期応答APIを要求する例を見てみましょう.
最近あまり使われていませんが、jqueryのajaxを例に挙げます.
const getUsers = () => {
  const Users = [];
  $.ajax({
    type: "GET",
    url: `http://someAPI/users`,
    dataType: "json",
    data: {},
  })
  .done((response) => {
    Users = response;
  });

  return Users;
}

console.log(getUsers); // undefined
APIからの応答出力が期待されるが、出力は未定義である.どうしてですか.get関数の応答結果を待たないため、return Usersコードはすぐに実行されます.
この問題はコールバック関数で解決したが,コールバック関数が重なるほど可読性が悪くなるという欠点がある.そしてPromiseが登場

2. Promise


Promiseは同期して動作し、非同期のように見えます.
Promiseを上記のajaxの例に適用します.
const getUsers = () => {
  return new Promise((resolve, reject) => {
    $.ajax({
      type: "GET",
      url: `http://someAPI/users`,
      dataType: "json",
      data: {},
    })
    .done((response) => {
      resolve(response);
    })
    .fail((xhr, status, error) => {
      reject(error);
    })
  });
}

getUsers()
  .then((response) => { console.log(response); })
  .catch((error) => { console.log(error); });
これでユーザーは正常に出力されます.どうしてこんなことになったの?
getUsers関数はPromiseを返します.Promiseはパラメータとしてexecutorというコールバック関数を持ち,Promise実装と同時にexecutor関数を実行する.
executorはresolve関数とexecute関数をパラメータとします.resolve関数が実行されている場合はPromiseがうまく実行されていることを示し、execute関数が実行されている場合はPromiseが実行できないことを示します.
そして、返されるPromiseの後ろにthen関数とcatch関数があるかもしれません.
その後、catchはPromiseの実行(解析または拒否)が実行されるまで待機します.
そして、関数は、Promiseが完了したとき(すなわち、Promiseの解析関数が実行されたとき)に実行される.そして,関数はパラメータとしてonResolveを受け入れ,このPromiseが解析関数を実行する際のパラメータである.
上記の例では、APIの応答結果、すなわち応答結果出力を解析した.
catch関数はPromiseが拒否されたときに実行されます.catch関数もthen関数と同様に,このPromiseのonRejectをパラメータとして受け入れる.
上記の例では、APIリクエストの受信および出力に失敗したときに受信したエラーをパラメータとして使用します.
では、例のコードを読みましょう.
getUsers関数を実行すると、Promiseが戻ってexecutorを実行します.ajaxを介してsomeAPIにgetリクエストを送信し、リクエストが成功すると応答結果を解析し、リクエストが失敗するとエラー内容を拒否します.
解析実行後、API応答結果が実行され出力されます.実行が拒否されると、catchが実行され、エラー内容が出力されます.
詳細は、MDNのPromise DocsおよびPromise作成者Docsに表示される.
これがPromiseの基本概念です.

3. async await


また、読みやすくする文法はasyncとwaitです.
asyncとawaitは新鮮なものではなく、PromiseとThat,catchに基づいて作成された文法です.
上記のPromiseの例にasync awaitを適用します.
const getUsers = () => {
  return new Promise((resolve, reject) => {
    $.ajax({
      type: "GET",
      url: `http://someAPI/users`,
      dataType: "json",
      data: {},
    })
    .done((response) => {
      resolve(response);
    })
    .fail((xhr, status, error) => {
      reject(error);
    })
  });
}

const prtinUsers = async () => {
  try {
    const users = await getUsers();
    console.log(users);
  } catch(error) {
    console.log(error);
  }
}
asyncは関数の宣言の前に続いています.async宣言を追加する関数はasyncFunctionとなります.
また、asyncFunctionが返す値はPromiseです.resolve()onResolveと同じです.
awaitは、AsyncFunctionの内部でのみ使用可能な構文です.待ってからPromiseが来るはずです.待ってから、Promiseが来たら、Promiseの実行を待ちます.
上記の例では、getUsers関数が返すのを待つPromiseを実行し、解析した値をuser変数に含めて出力します.
async/await構文はthen/catch構文と比較して最近出現した.どちらがいいかは言いにくいですが、私にとってasync/await文法はコードを読みやすいので、もっと好きです.

4.Promiseとthen/catchを私のプロジェクトに適用する


そしてこれを私のプロジェクトに適用します.そして結果はこれ
import axios, { AxiosResponse } from "axios";

import { API_KEY } from "../config";
import { RankEntryResponseT, SummonerPayloadT, SummonerInfoResponseT, SummonerResponseT } from "../types/types";

export const getSummoner = ( summonerPayload: SummonerPayloadT ): Promise<SummonerResponseT> => {
  const { summonerName } = summonerPayload;

  const TFT_API = axios.create({
    baseURL: `/tft`,
    headers: {
      "X-Riot-Token": API_KEY
    }
  })

  return new Promise((resolve, reject) => {
      TFT_API
        .get(`/summoner/v1/summoners/by-name/${summonerName}`)
        .then((summonerInfoResponse: AxiosResponse<Promise<SummonerInfoResponseT>>): Promise<SummonerInfoResponseT> => {
          return new Promise((resolve) => {
            resolve(summonerInfoResponse.data);
          })
        })
        .then((summonerInfoResponseData: SummonerInfoResponseT) => {
          const encryptedSummonerId = summonerInfoResponseData.id;

          TFT_API
            .get(`/league/v1/entries/by-summoner/${encryptedSummonerId}`)
            .then((rankEntryResponse: AxiosResponse<RankEntryResponseT[]>) => {
              resolve({
                summonerInfo: summonerInfoResponseData,
                rankEntry: rankEntryResponse.data
              })
            })
        })
        .catch((err) => reject(err));
  });
}
ざっと見ても読みやすいコードではありません.むしろ起動しても、悪いコードです.axiosがPromiseを返すのはもっと混同されていて、何を返すのか分からないので、Type Scriptを使う部分でも混同されています.TypeScriptは初めてなのでそれも難しいです
とにかく...これをasync/awaitに変えるべきだと思います.

4.1. async/await再包装


コアはaxiosリクエストがPromiseを返し、async関数が返す値はPromiseです.決意です.
次にasync/awaitで修正した結果を示します.
import axios, { AxiosResponse } from "axios";

import { API_KEY } from "../config";
import { RankEntryResponseT, SummonerPayloadT, SummonerInfoResponseT, SummonerResponseT } from "../types/types";

export const asyncGetSummoner = async (summonerPayload: SummonerPayloadT): Promise<SummonerResponseT> => {
  const { summonerName } = summonerPayload;

  const TFT_API = axios.create({
    baseURL: `/tft`,
    headers: {
      "X-Riot-Token": API_KEY
    }
  })

  const summonerInfoResponse: AxiosResponse<SummonerInfoResponseT> = await TFT_API.get(`/summoner/v1/summoners/by-name/${summonerName}`);
  const encryptedSummonerId = summonerInfoResponse.data.id;

  const rankEntryResponse: AxiosResponse<RankEntryResponseT[]> = await TFT_API.get(`/league/v1/entries/by-summoner/${encryptedSummonerId}`);

  const summonerResponse: SummonerResponseT = {
    summonerInfo: summonerInfoResponse.data,
    rankEntry: rankEntryResponse.data
  };

  return summonerResponse;
}
どうですか.ずっときれいになったのではないでしょうか.コードはよく読めて、とても満足していると思います.
とにかく...これだけです.

🍓


この文章の主旨はPromiseに対する私のさらなる理解を記録したいということです.読みにくいAPIリクエストコードの書き直しに成功できて嬉しいです.
もちろん、知識が増えるにつれて、もっと削減できる部分が見えてきます.