技術共有

ES6の非同期機能の詳しい説明(10)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

非同期関数とは何ですか?一言で言えば、ジェネレーター関数の糖衣構文です。

const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

async 関数は、Generator 関数のアスタリスク (*) を async に置き換え、yield を await に置き換えるだけです。

Generator 関数に対する async 関数の改善は、次の 4 つの点に反映されています。

(1) アクチュエータを内蔵しています。
Generator 関数の実行はエグゼキュータに依存する必要があるため、co モジュールがあり、async 関数には独自のエグゼキュータが付属しています。つまり、非同期関数の実行は通常の関数とまったく同じで、たった 1 行で実行できます。

co モジュール: co モジュールは、2013 年 6 月に有名なプログラマー TJ Holowaychuk によってリリースされた小さなツールで、ジェネレーター関数の自動実行に使用されます。
co モジュールを使用すると、Generator 関数のエグゼキューターを作成する手間が省けます。

// Generator 函数
var gen = function* () {
  var f1 = yield readFile('/etc/fstab');
  var f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

//co模块使用
var co = require('co');
co(gen); //co 函数返回一个 Promise 对象
co(gen).then(function (){
  console.log('Generator 函数执行完成');
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(2) セマンティクスの改善。
async と await は、アスタリスクや yield よりも明確なセマンティクスを持っています。 async は関数内に非同期操作があることを意味し、await は次の式が結果を待つ必要があることを意味します。
(3) 適用範囲が広がります。
co モジュールの規則によれば、yield コマンドの後には Thunk 関数または Promise オブジェクトのみを続けることができますが、async 関数の await コマンドの後には Promise オブジェクトとプリミティブ型の値 (数値、文字列、およびブール値) を続けることができます。値ですが、すぐに解決された Promise オブジェクトに自動的に変換されます)。
(4) 戻り値は Promise です。
async 関数の戻り値は Promise オブジェクトであり、Generator 関数の戻り値が Iterator オブジェクトであるよりもはるかに便利です。 then メソッドを使用して、次のアクションを指定できます。

さらに、async 関数は、Promise オブジェクトにパッケージ化された複数の非同期操作とみなすことができ、await コマンドは内部の then コマンドの構文糖となります。

1. 基本的な非同期関数

// 定义一个异步函数
async function fetchData() {
    return 'Data fetched';
}

// 调用异步函数
fetchData().then(data => {
    console.log(data); // 输出: Data fetched
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2. await を使用して Promise を待ちます

// 模拟一个异步请求函数
function getUserData() {
    return new Promise(resolve => {
        setTimeout(() => resolve({ name: 'Alice' }), 1000);
    });
}

// 异步函数使用 await 等待 Promise
async function printUserData() {
    try {
        const userData = await getUserData();
        console.log(userData); // 输出: { name: 'Alice' }
    } catch (error) {
        console.error(error);
    }
}

printUserData();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

3. エラー処理

// 异步函数中的错误处理
async function riskyFunction() {
    try {
        const result = await Promise.reject('An error occurred');
    } catch (error) {
        console.error(error); // 输出: An error occurred
    }
}

riskyFunction();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4. 連鎖した非同期関数

async function asyncOperation() {
    return 'Operation completed';
}

async function chainAsyncFunctions() {
    try {
        const result1 = await asyncOperation();
        const result2 = await asyncOperation();
        console.log(result1, result2); // 输出: Operation completed Operation completed
    } catch (error) {
        console.error(error);
    }
}

chainAsyncFunctions();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

5. イベント処理関数としての async 関数

// 假设有一个按钮元素
const button = document.querySelector('#myButton');

// 为按钮添加点击事件处理函数
button.addEventListener('click', async event => {
    try {
        const data = await fetchData();
        console.log(data);
    } catch (error) {
        console.error(error);
    }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

6. async関数とPromise.all

// 异步函数返回多个 Promise
async function fetchUsers() {
    return ["User1", "User2", "User3"];
}

async function fetchPosts() {
    return ["Post1", "Post2", "Post3"];
}

// 使用 Promise.all 并行处理多个异步操作
async function fetchAllData() {
    try {
        const [users, posts] = await Promise.all([fetchUsers(), fetchPosts()]);
        console.log(users, posts); // 输出: [ 'User1', 'User2', 'User3' ] [ 'Post1', 'Post2', 'Post3' ]
    } catch (error) {
        console.error(error);
    }
}

fetchAllData();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20