>  기사  >  웹 프론트엔드  >  JavaScript의 약속: 비동기 코드 이해, 처리 및 마스터

JavaScript의 약속: 비동기 코드 이해, 처리 및 마스터

WBOY
WBOY원래의
2024-09-03 14:18:32739검색

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

소개

저는 Java 개발자로 일했는데 처음으로 JavaScript의 Promise를 접했던 기억이 납니다. 개념은 단순해 보이지만 Promise가 어떻게 작동하는지 완전히 이해할 수는 없었습니다. 프로젝트에서 이를 사용하기 시작하고 그들이 해결한 사례를 이해했을 때 상황이 바뀌었습니다. 그러다가 AHA 순간이 왔고 모든 것이 더욱 명확해졌습니다. 시간이 지나면서 Promises는 내 도구 벨트의 귀중한 무기가 되었습니다. 업무에서도 사용할 수 있고, 기능 간 비동기 처리도 해결되면 묘한 만족감을 줍니다.

아마도 API에서 데이터를 가져올 때 Promise를 처음 접하게 될 것입니다. 이는 가장 일반적인 예이기도 합니다. 최근 인터뷰를 했는데 첫 번째 질문인 “Promise와 Async Await의 차이점을 알려주실 수 있나요?”가 무엇이었을까요? 나는 그것이 지원자가 메커니즘의 작동 방식을 어떻게 이해하는지 더 잘 알 수 있는 좋은 출발점이라고 생각하기 때문에 이를 환영합니다. 그러나 그 또는 그녀는 대부분 다른 라이브러리와 프레임워크를 사용하고 있습니다. 차이점을 기록하고 비동기 함수 오류 처리에 대한 모범 사례를 설명할 수 있었습니다.

약속은 무엇입니까

첫 번째 질문인 "약속은 무엇입니까?"부터 시작하겠습니다. Promise는 우리가 아직 모르는 값에 대한 자리 표시자이지만 비동기 계산/함수의 결과로 값을 얻게 됩니다. 약속이 잘되면 결과가 나오겠죠. Promise가 제대로 진행되지 않으면 Promise는 오류를 반환합니다.

약속의 기본 예

약속 정의

생성자를 호출하고 두 개의 콜백 함수인 해결거부를 전달하여 Promise를 정의합니다.

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

Promise를 성공적으로 해결하려면 해결 함수를 호출합니다. Reject는 로직을 평가하는 동안 오류가 발생할 경우 Promise를 거부하는 것입니다.

Promise 결과 조회

Promise의 결과를 얻기 위해 내장된 함수를 사용합니다. 두 개의 전달된 콜백(결과 및 오류)이 있습니다. Resolve 함수에 의해 Promise가 성공적으로 해결되면 결과가 호출됩니다. Promise가 해결되지 않으면 두 번째 함수 오류가 호출됩니다. 이 함수는 거부 또는 발생한 다른 오류에 의해 트리거됩니다.

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

이 예에서는 Promise를 성공적으로 해결했기 때문에 Hello라는 결과를 얻게 됩니다.

약속의 오류 처리

Promise가 거부되면 항상 두 번째 오류 콜백이 호출됩니다.

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 중 하나가 거부되면 Promise.all도 거부됩니다.

경주 약속

또 다른 기본 제공 기능은 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를 작성하려면 많은 상용구 코드가 필요합니다. 운 좋게도 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.