Callback Hell の解決策: Promise、async/await、Generator

コールバック関数とは何ですか?

関数を引数として別の引数に渡し、その関数がすぐに実行されない場合、その関数は特定の条件が満たされた場合にのみ実行されます.この関数はコールバック関数と呼ばれます. コールバック関数はタイマーと Ajax に存在します。

タイマー:

setTimeout(function () {
      console.log("执行回调函数")
}, 3000)

function () {console.log("execute callback function")} はコールバック関数で、3 秒後に実行されます。

アヤックス:

// 创建异步对象
const xhr = new XMLHttpRequest();
// 请求路径
const url = 'http://localhost:3000/getData';
// 绑定监听事件
xhr.onreadystatechange = function () {
    console.log(this.readyState);
    // 这个方法会被调用4次,最后一次readyState=4,并且status=200时才是最终想要的响应结果
    if (this.readyState == 4 && this.status == 200) {
      // 响应数据
      const response = xhr.responseText;
      console.log(response);
    }
}
// 创建请求
xhr.open('GET', url);
// 发送请求
xhr.send();

ここで onreadystatechange にバインドされている関数は、リクエストを送信してレスポンスを取得した後に実行されるコールバック関数です。

コールバック地獄とは?

コールバック地獄は非同期 js だけにあり、コールバック関数が多すぎて、コールバック内にコールバックが設定されているため、コードの可読性が低下します。

要件の実行は、最初にステップ 1 を実行し、次にステップ 2 を実行し、次にステップ 3 を実行します。

コールバック地獄の書き方:

setTimeout(function () {
      console.log("步骤一")
      setTimeout(function () {
        console.log("步骤二")
        setTimeout(function () {
          console.log("步骤三")
        }, 1000)
      }, 1000)
}, 1000)

コールバック地獄を解決するには?

1. Promise を使用する

Promise は、従来のソリューション (コールバック関数とイベント) よりも論理的で強力な非同期プログラミングのソリューションです。コミュニティによって最初に提案され、実装されました. ES6 はそれを言語標準に書き込み、使用法を統一し、Promise オブジェクトをネイティブに提供しました.

  • Promise コンストラクターは関数をパラメーターとして受け取り、処理する必要がある非同期タスクは関数の本体に記述されます. 関数の 2 つのパラメーターは resolve と reject です. 非同期タスクが正常に実行されたら、resolve 関数を呼び出して結果を返します。それ以外の場合は reject を呼び出します。
  • Promise オブジェクトの then メソッドは、処理が成功した場合の応答データを受け取るために使用され、catch メソッドは、処理が失敗した場合に対応するデータを受け取るために使用されます。
  • Promise のチェーンプログラミングはコードの実行順序を保証できるが、then を処理した後は毎回 Promise オブジェクトを返さなければならず、次の then でデータを受信できることが前提となる。
const getOne = function (id) {
      console.log('步骤一:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 1});
      })
}
const getTwo = function (id) {
      console.log('步骤二:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 2});
      })
}
const getThree = function (id) {
      console.log('步骤三:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 3});
      })
}

getOne('one').then((res) => {
      console.log(res);
      return getTwo('two')
}).then((res) => {
      console.log(res);
      return getThree('three')
}).then((res) => {
      console.log(res)
}).catch((e) => {
      console.log(e);
})

2. async/await を使用する

es8 async の新機能であり
、await は同期コードのような非同期コードを作成できます。

  • async は、これが非同期関数であることを示します。await を async 関数に記述する必要があります。
  • await の右側の式は一般的に promise オブジェクトです
  • await は promise 成功の値を返します
  • await の promise が失敗した場合、例外がスローされます。これは、try...catch によってキャプチャおよび処理する必要があります。
  • 返された結果が Promise オブジェクトでない場合 (戻り文字列、数値型など、未定義な​​ど)、関数によって返された結果は成功した Promise オブジェクトです。
  • 返された結果が promise オブジェクトの場合、成功した promise の値は成功した関数の値です
const getOne = function (id) {
      console.log('步骤一:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 1});
      })
}
const getTwo = function (id) {
      console.log('步骤二:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 2});
      })
}
const getThree = function (id) {
      console.log('步骤三:', id);
      return new Promise((resolve, reject) => {
        resolve({result: true, text: 3});
      })
}

const makeRequest = async () => {
      try {
        const data1 = await getOne('one');
        console.log(data1)
        if (data1) {
          const data2 = await getTwo('two');
          console.log(data2)
          if (data2) {
            const data3 = await getThree('three');
            console.log(data3)
          }
        }
      } catch (e) {
        console.log(e)
      }
}
makeRequest();

3. ジェネレーターを使用する

Generator は、ES6 によって提案された非同期プログラミング ソリューションです。イテレータを手動で作成するのは非常に面倒なので、ES6 ではジェネレータを導入してイテレータをより便利に作成できるようになりました。つまり、ジェネレーターはイテレーター オブジェクトを返す関数です。

ジェネレーター(generator)は関数で、宣言方法は通常の関数と同様ですが、関数の後に*(関数*)を追加する必要がある以外は、
ジェネレーター(generator)は特別な関数で、定義方法と実行方法は同じです通常の機能と同じではありません。

  • ジェネレーターは、非同期プログラミングのコールバック地獄の問題を解決するための特別な関数 (関数名の前に * を追加) であり、その構文と動作は従来の関数とはまったく異なります。
  • yield ステートメントは関数コードの区切りであり、関数コードをいくつかの部分に分割し、next() を介してコードの下位実行を制御します。
  • iterator を使用する iterator オブジェクトは、for...of を使用してトラバースできることを示します。各呼び出しによって返される結果は、yield 後のコンテンツです。
  • next が実行されると、パラメーターを渡すことができ、パラメーターは前の yield ステートメント全体の結果として返されます。
const getOne = function (id) {
      console.log('步骤一:', id);
      setTimeout(() => {
        iterator.next({result: true, text: 1});
      }, 1000);
}
const getTwo = function (id) {
      console.log('步骤二:', id);
      setTimeout(() => {
        iterator.next({result: true, text: 2});
      }, 1000);
}
const getThree = function (id) {
      console.log('步骤三:', id);
      setTimeout(() => {
        iterator.next({result: true, text: 3});
      }, 1000);
}

function* gen() {
      const data1 = yield getOne('one');
      console.log(data1)
      const data2 = yield getTwo('two');
      console.log(data2)
      const data3 = yield getThree('three');
      console.log(data3)
}

let iterator = gen();
iterator.next();

おすすめ

転載: blog.csdn.net/qq_39998026/article/details/125800152