宣言JavaScript約束ラッパーを書く方法


執筆Vijit Ail ✏️
JavaScriptは単一のスレッドプログラミング言語であり、同期的にコードを実行することができます.しかしasynchronous programming この問題に対処するために導入されました.
このコアJavaScriptの概念は、他の関数が実行を終了するのを待ちながら実行する機能を可能にします.バックエンドへのAPI呼び出しを行うために非同期関数を使用します.また、それらを使用してファイルやデータベースに書き込み、読み込みます.このコンセプトは、サーバー側の開発者とクライアント側の開発者に便利です.
このガイドでは、JavaScriptの宣言非同期関数呼び出しを記述する方法を示します.また、どのように我々のコードをより読みやすく、維持するのに役立ちます.

宣言型プログラミング


コードへのダイビング前に、宣言型プログラミングパターンを確認しましょう.
宣言的プログラミングは一般的にコードの論理を示すプログラミングパラダイムであるが、そこにたどり着くためのステップではない.プログラミングのこのタイプでは、それは一般的に何が舞台裏で起こっているか明らかではない.
逆に、命令プログラミングは、各ステップを詳細に説明した段階的なコードを書く必要があります.これは、コードで動作する必要があります将来の開発者のための有用な背景を提供することができますが、それは非常に長いコードになります.命令プログラミングはしばしば不要ですそれは我々の目的次第だ.
宣言型プログラミングは、作り付けのJavaScriptメソッドを使用して実現できます.宣言型プログラミングでは、読みやすいコードを書くことができます.
たとえば、宣言型プログラミングではfor ループを配列で繰り返します.代わりに、組み込みの配列メソッドを使用することができますmap() , reduce() , and forEach() .
ここでは命令のプログラミング例を示しますfor ループ
const reverseString = (str) => {
    let reversedString = "";

    for (var i = str.length - 1; i >= 0; i--) { 
        reversedString += str[i];
    }
    return reversedString; 
}
しかし、なぜ私たちがコードのちょうど2行で同じ解決を達成することができるコードの10行を書くか?
JavaScriptの作り付けられた配列メソッドを使用して、同じコードの宣言的なプログラミングバージョンです.
const reverseString = (str) => {
  return str.split("").reverse().join("");  
} 
このコードスニペットは2行のコードを使用して文字列を反転します.それは非常に短く、ポイントにまっすぐになる.

JavaScriptで約束する


エーpromise 非同期関数の結果を含むJavaScriptオブジェクトです.言い換えれば、それは非同期関数で完了したか失敗したタスクを表します.
const promise = new Promise (function (resolve, reject) {
    // code to execute
})
The promise コンストラクタは1つの引数をとります.executor関数はコールバック関数を2つ取ります:resolve and reject . を返します.resolve() メソッドが呼び出され、promise 保留中から状態に変化します.を返します.reject() メソッドが呼び出され、promise 保留中の状態への状態の変更.
解決値にアクセスするには、.then () とチェーンするメソッドpromise , 下記の通り.
promise.then(resolvedData => {
  // do something with the resolved value
})
同様に、拒否値の場合は.catch() メソッドを使用します.
promise.then(resolvedData => {
  // do something with the resolved value
}).catch(err => {
  // handle the rejected value
})

非同期/待機


いくつかのネストされたコールバックまたは.then 関数は、しばしばコードとその読みやすさを維持するのが難しくなります.
The async キーワードは、JavaScriptの非同期操作を処理する関数を定義するのに役立ちます.一方、await キーワードは、JavaScriptエンジンに結果を返す前に関数が完了するのを待つよう指示します.
async/wait it構文は約束の周りの構文上の砂糖です.それは私たちが維持するために簡単ですクリーナーコードを達成するのに役立ちます.
const getUsers = async () => {
  const res = await fetch('https://jsonplaceholder.typicode.com/users');
  const data = await res.json();
  return data;
}
async/waitは、約束または非同期関数を同期的に実行できるようにします.しかし、ラップするのは常に良い練習ですawait とのキーワードtry...catch 予期しないエラーを避けるためにブロックします.
ここでは、ラップをラップする例ですawait キーワードとgetUsers() 関数はtry...catch ブロック:
const onLoad = async () => {
  try {
    const users = await getUsers();
    // do something with the users
  } catch (err) {
    console.log(err)
    // handle the error
  }
}

カスタムプロミスラッパー


async/waitが現代のJavascriptのそのようなものすごい特徴である理由の1つは、それがコールバック地獄を避けるのを援助するということです.
それでも、async 関数は次のようになります.
try {
  const a = await asyncFuncOne();
} catch (errA) {
  // handle error
}

try {
  const b = await asyncFunctionTwo();
} catch (errB) {
  // handle error
}

try {
  const c = await asyncFunctionThree();
} catch (errC) {
  // handle error
}
我々がすべてを加えるならばasync つの関数try ブロック、我々は複数の書き込みを終了しますif コンディションcatch ブロックからcatch ブロックは、より一般的です
try {
  const a = await asyncFuncOne();
  const b = await asyncFunctionTwo();
  const c = await asyncFunctionThree();
} catch (err) {
  if(err.message.includes('A')) {
    // handle error for asyncFuncOne
  }
  if(err.message.includes('B')) {
    // handle error for asyncFunctionTwo
  }
  if(err.message.includes('C')) {
    // handle error for asyncFunctionThree
  }
}
これは、非同期/待機構文を使用しても、コードを読みにくく、維持するのが困難になります.
この問題を解決するために、我々は、約束をラップし、繰り返しを避けるユーティリティ機能を書くことができますtry...catch ブロック.
ユーティリティ関数は、パラメーターとしての約束を受け入れ、エラーを内部的に処理し、2つの要素を持つ配列を返します.
この関数は、その約束を解決し、配列の最初の要素のデータを返します.エラーは配列の2番目の要素で返されます.約束が解決されるならば、第2の要素はnull .
const promiser = async (promise) => {
  try {
    const data = await promise;
    return [data, null]
  } catch (err){
    return [null, error]
  }
}
さらに、上記のコードをリファクタリングし、try...catch ブロックを返すだけでpromise 使用.then() and .catch() ハンドラメソッド:
const promiser = (promise) => {
  return promise.then((data) => [data, null]).catch((error) => [null, error]);
};
以下のユーティリティの使い方を見ることができます.
const demoPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve("Yaa!!");
    reject("Naahh!!");
  }, 5000);
});

const runApp = async () => {
  const [data, error] = await promiser(demoPromise);
  if (error) {
    console.log(error);
    return;
  }
  // do something with the data
};

runApp();
さて、現実のユースケースを見てみましょう.下記generateShortLink 関数は、完全な長さのURLを短縮するURL短縮サービスを使用します.
ここでaxios.get() メソッドはpromiser() URL短縮サービスからレスポンスを返す機能.
import promiser from "./promise-wrapper";
import axios from "axios";

const generateShortLink = async (longUrl) => {
  const [response, error] = await promiser(
    axios.get(`https://api.1pt.co/addURL?long=${longUrl}`)
  );

  if (error) return null;

  return `https://1pt.co/${response.data.short}`;
};
比較のために、この関数はpromiser() ラッパー関数
const generateShortLink = async (longUrl) => {
  try {
    const response = await axios.get(
      `https://api.1pt.co/addURL?long=${longUrl}`
    );
    return `https://1pt.co/${response.data.short}`;
  } catch (err) {
    return null;
  }
};
では、この例を使用してフォームを作成してくださいgenerateShortLink() メソッド:
const form = document.getElementById("shortLinkGenerator");

const longUrlField = document.getElementById("longUrl");

const result = document.getElementById("result");

form.addEventListener("submit", async (e) => {
  e.preventDefault();
  const longUrl = longUrlField.value;
  const shortLink = await generateShortLink(longUrl);
  if (!shortLink) result.innerText = "Could not generate short link";
  else result.innerHTML = `<a href="${shortLink}">${shortLink}</a>`;
});

<!-- HTML -->
<!DOCTYPE html>
<html>
  <head>
    <title>Demo</title>
    <meta charset="UTF-8" />
  </head>
  <body>
    <div id="app">
      <form id="shortLinkGenerator">
        <input type="url" id="longUrl" />
        <button>Generate Short Link</button>
      </form>
      <div id="result"></div>
    </div>
    <script src="src/index.js"></script>
  </body>
</html>
ここではcomplete code and demo 参考のために.
これまでpromiser() 機能はシングルのみをラップできるasync 関数.しかし、ほとんどのユースケースでは、複数のasync 関数.
多くの約束を処理するためにPromise.all() メソッドとasync 関数はpromiser 機能
const promiser = (promise) => {
  if (Array.isArray(promise)) promise = Promise.all(promise);
  return promise.then((data) => [data, null]).catch((error) => [null, error]);
};
以下に例を示しますpromiser() 複数関数async 機能
import axios from "axios";
import promiser from "./promiser";

const categories = ["science", "sports", "entertainment"];

const requests = categories.map((category) =>
  axios.get(`https://inshortsapi.vercel.app/news?category=${category}`)
);

const runApp = async () => {
  const [data, error] = await promiser(requests);
  if (error) {
    console.error(error?.response?.data);
    return;
  }
  console.log(data);
};

runApp();

結論


JavaScriptで宣言的な非同期関数呼び出しを記述するためのこのガイドで共有されるソリューションは、ほとんどのシナリオに最適です.ただし、考慮する必要があります追加のユースケースがあります.たとえば、予期したエラーのみを処理し、Promise実行中に発生した例外的なエラーをスローします.
どんなアプローチにもトレードオフがある.それはあなたの特定のユースケースのために理解し、それらを考慮に入れることが重要です.
この記事で共有されている知識は、あなたのコーディングの旅を続けると、より複雑なAPIとユーティリティ関数を作成するための良いエントリポイントです.幸運とハッピーコーディング!

デバッグ:JavaScriptのエラーをデバッグする


デバッグコードは常に退屈な作業です.しかし、より多くのあなたのエラーを理解しやすく、それを修正することです.
LogRocket 新しいユニークな方法でこれらのエラーを理解することができます.当社のフロントエンド監視ソリューションは、ユーザーがあなたの能力を正確に何がエラーにつながったかを見つけるために能力を与えるためにJavaScriptフロントエンドとのユーザーの関与を追跡します.

LogRocketレコードコンソールログ、ページの読み込み時間、StackTraceは、低速ネットワークのリクエスト/応答ヘッダー/本文、ブラウザのメタデータ、およびカスタムログ.JavaScriptコードの影響を理解することは容易になります!
Try it for free .