ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript の約束: 非同期コードの理解、処理、および習得

JavaScript の約束: 非同期コードの理解、処理、および習得

WBOY
WBOYオリジナル
2024-09-03 14:18:32739ブラウズ

Promises in JavaScript: Understanding, Handling, and Mastering Async Code

イントロ

私は Java 開発者として働いていましたが、JavaScript の Promise に初めて触れたときのことを覚えています。コンセプトは単純そうに見えましたが、Promise がどのように機能するのかを完全に理解することはできませんでした。プロジェクトでそれらを使用し始め、それらが解決したケースを理解したとき、状況は変わりました。その後、AHA の瞬間が到来し、すべてがより明確になりました。時間が経つにつれて、Promise は私のツールベルトの貴重な武器になりました。仕事でそれらを使用して、関数間の非同期処理を解決できると、妙に満足です。

おそらく、API からデータをフェッチするときに最初に Promise に遭遇するでしょう。これは最も一般的な例でもあります。最近、インタビューを受けたことがありますが、「Promise と Async Await の違いを教えていただけますか?」という最初の質問は何だったでしょうか。これは、申請者がメカニズムの仕組みをどのように理解しているかをより深く知るための良い出発点であると考えているため、これを歓迎します。ただし、主に他のライブラリやフレームワークを使用しています。これにより、違いを書き留め、非同期関数のエラーを処理するための優れた実践方法を説明することができました。

約束とは何ですか

最初の質問から始めましょう:「約束とは何ですか?」 Promise はまだ不明な値のプレースホルダーです が、非同期計算/関数の結果として取得されます。約束がうまくいけば、結果が得られます。 Promise がうまくいかない場合、Promise はエラーを返します。

Promise の基本的な例

約束を定義する

Promise を定義するには、そのコンストラクターを呼び出し、2 つのコールバック関数 resolvereject を渡します。

const newPromise = new Promise((resolve, reject) => {
    resolve('Hello');
    // reject('Error');
});

Promise を正常に解決したい場合は、resolve 関数を呼び出します。拒否は、ロジックの評価中にエラーが発生した場合に Promise を拒否するためのものです。

Promise 結果の取得

次に、組み込み関数を使用して Promise の結果を取得します。これには、結果とエラーという 2 つのコールバックが渡されます。 Promise が関数 replace によって正常に解決されると、result が呼び出されます。 Promise が解決されない場合、2 番目の関数エラーが呼び出されます。この関数は、拒否またはスローされた別のエラーによってトリガーされます。

newPromise.then(result => {
    console.log(result); // Hello
}, error => {
    console.log("There shouldn't be an error");
});

この例では、Promise が正常に解決されたため、Hello という結果が得られます。

Promise のエラー処理

Promise が拒否されると、常に 2 番目のエラー コールバックが呼び出されます。

const newPromise1 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise1');
});

newPromise1.then(
  (result) => {
    console.log(result); // It is not invoked
  },
  (error) => {
    console.log(error); // 'An error occurred in Promise1'
  }
);

わかりやすくするために、より推奨されるアプローチは、組み込みの catch メソッドを使用することです。

const newPromise2 = new Promise((resolve, reject) => {
  reject('An error occurred in Promise2');
});

newPromise2
  .then((result) => {
    console.log(result); // It is not invoked
  })
  .catch((error) => {
    console.log(error); // 'An error occurred in Promise2'
  });

catch メソッドはチェーンされており、独自のエラー コールバックを提供しています。 Promise が拒否された場合に呼び出されます。

どちらのバージョンも正常に機能しますが、チェーンは IMO でより読みやすく、さらに説明する他の組み込みメソッドを使用するときに便利です。

約束を連鎖させる

約束の結果は、別の約束になる可能性があります。その場合、任意の数の then 関数を連鎖させることができます。

getJSON('categories.json')
    .then(categories => {
        console.log('Fetched categories:', categories);

        return getJSON(categories[0].itemsUrl);
    })
    .then(items => {
        console.log('Fetched items:', items);

        return getJSON(items[0].detailsUrl);
    })
    .then(details => {
        console.log('Fetched details:', details);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

この例では、検索結果を絞り込んで詳細データを取得します。各 then 関数にはエラー コールバックを含めることもできます。呼び出しチェーン内のエラーをキャッチすることだけを気にする場合は、catch 関数を活用できます。いずれかの Promise がエラーを返した場合に評価されます。

みんなと約束してね

時には、より独立した約束の結果を待ち、その結果に基づいて行動したいと思うことがあります。 Promise が解決される順序を気にしない場合は、組み込み関数 Promise.all を使用できます。

Promise.all([
    getJSON('categories.json'),
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(results => {
        const categories = results[0];
        const techItems = results[1];
        const scienceItems = results[2];

        console.log('Fetched categories:', categories);
        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);

        // Fetch details of the first item in each category
        return Promise.all([
            getJSON(techItems[0].detailsUrl),
            getJSON(scienceItems[0].detailsUrl)
        ]);
    })
    .then(detailsResults => {
        const laptopDetails = detailsResults[0];
        const physicsDetails = detailsResults[1];

        console.log('Fetched laptop details:', laptopDetails);
        console.log('Fetched physics details:', physicsDetails);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

Promise.all は Promise の配列を受け取り、結果の配列を返します。 Promise の 1 つが拒否された場合、Promise.all も拒否されます。

レースの約束

もう 1 つの組み込み機能は Promise.race です。これは、複数の非同期関数 (Promise) があり、それらを競合させたい場合に使用されます。

Promise.race([
    getJSON('technology_items.json'),
    getJSON('science_items.json')
])
    .then(result => {
        console.log('First resolved data:', result);
    })
    .catch(error => {
        console.error('An error has occurred:', error.message);
    });

Promise の実行にはさまざまな時間がかかる場合があり、Promise.race は配列から最初に解決または拒否された Promise を評価します。順序は気にしないが、最速の非同期呼び出しの結果が必要な場合に使用されます。

非同期待機とは何ですか

ご覧のとおり、Promise を記述するには多くの定型コードが必要です。幸いなことに、ネイティブの Async Await 機能があるため、Promise の使用がさらに簡単になります。関数を async という単語でマークします。これにより、コードのどこかで非同期関数を呼び出すので、それを待つ必要がないことを示します。次に、await ワードを使用して async 関数が呼び出されます。

Basic example of Async Await

const fetchData = async () => {
    try {
        // Fetch the categories
        const categories = await getJSON('categories.json');
        console.log('Fetched categories:', categories);

        // Fetch items from the first category (Technology)
        const techItems = await getJSON(categories[0].itemsUrl);
        console.log('Fetched technology items:', techItems);

        // Fetch details of the first item in Technology (Laptops)
        const laptopDetails = await getJSON(techItems[0].detailsUrl);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error has occurred:', error.message);
    }
};

fetchData();

Our fetchData is marked as async and it allows us to use await to handle asynchronous calls inside the function. We call more Promises and they will evaluated one after the other.

We use try...catch block if we want handle the errors. Rejected error is then caught in the catch block and we can act on it like logging the error.

What’s different

They are both features of JavaScript handling with asynchronous code. The main difference is in the syntax when Promises use chaining with then and catch but async await syntax is more in synchronous way. It makes it easier to read. Error handling for async await is more straightforward when it leverages try...catch block. This is a question that you can easily get at the interview. During the answer, you can get deeper into the description of both and highlight those differences.

Promise features

Of course, you can use all the features with async await. For example Promise.all.

const fetchAllData = async () => {
    try {
        // Use await with Promise.all to fetch multiple JSON files in parallel
        const [techItems, scienceItems, laptopDetails] = await Promise.all([
            getJSON('technology_items.json'),
            getJSON('science_items.json'),
            getJSON('laptops_details.json')
        ]);

        console.log('Fetched technology items:', techItems);
        console.log('Fetched science items:', scienceItems);
        console.log('Fetched laptop details:', laptopDetails);
    } catch (error) {
        console.error('An error occurred:', error.message);
    }
};

Practical use cases

Promises are a fundamental feature in JavaScript for handling asynchronous code. Here are the main ways it is used:

Fetching Data from APIs

As was already shown in the examples above, this is one of the most used use cases for Promises and you work with it daily.

Handling file operations

Reading and writing files asynchronously can be done using promises, especially by Node.js module fs.promises

import * as fs from 'fs/promises';

const writeFileAsync = async (filePath, content, options = {}) => {
    try {
        await fs.writeFile(filePath, content, options);
        console.log(`File successfully written to ${filePath}`);
    } catch (error) {
        console.error(`Error writing file to ${filePath}:`, error.message);
    }
};

const filePath = 'output.txt';
const fileContent = 'Hello, this is some content to write to the file!';
const fileOptions = { encoding: 'utf8', flag: 'w' }; // Optional file write options

writeFileAsync(filePath, fileContent, fileOptions);

Promise based libraries

Axios is library that you should be familiar with. Axios handles HTTP requests in client and is vastly used.

Express is a web framework for Node.js. It makes it easy to build web apps and APIs, and when you use promises with Express, your code stays clean and easy to manage.

Repository with examples

All the examples can be found at: https://github.com/PrincAm/promise-example

Summary

Promises are a fundamental part of JavaScript, essential for handling asynchronous tasks in web development. Whether fetching data, working with files, or using popular libraries like Axios and Express, you’ll frequently use promises in your code.

In this article, we explored what Promises are, how to define and retrieve their results, and how to handle errors effectively. We also covered key features like chaining, Promise.all, and Promise.race. Finally, we introduced async await syntax, which offers a more straightforward way to work with promises.

Understanding these concepts is crucial for any JavaScript developer, as they are tools you’ll rely on daily.

If you haven’t tried it yet, I recommend writing a simple code snippet to fetch data from an API. You can start with a fun API to experiment with. Plus, all the examples and code snippets are available in this repository for you to explore.

以上がJavaScript の約束: 非同期コードの理解、処理、および習得の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。