"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > JavaScript로 약속 취소 익히기

JavaScript로 약속 취소 익히기

2024-11-02에 게시됨
검색:809

로사리오 데 키아라가 작성✏️

자바스크립트에서 Promise는 비동기 작업을 처리하기 위한 강력한 도구로, 특히 UI 관련 이벤트에 유용합니다. 이는 즉시 사용할 수 없지만 향후 어느 시점에 해결될 값을 나타냅니다.

Promise를 사용하면 개발자가 API 호출, 사용자 상호 작용 또는 애니메이션과 같은 작업을 처리할 때 더 깔끔하고 관리하기 쉬운 코드를 작성할 수 있습니다. .then(), .catch() 및 .finally()와 같은 메서드를 사용하면 Promises를 통해 악명 높은 "콜백 지옥"을 피하면서 성공 및 오류 시나리오를 보다 직관적으로 처리할 수 있습니다.

이 문서에서는 새로운 Promise와 Promise를 해결하는 두 개의 함수, 세 가지를 포함하는 객체를 반환하여 더 깔끔하고 간단한 코드를 작성할 수 있는 새로운(2024년 3월 Promise.withResolvers() 메서드를 사용합니다. 다른 하나는 이를 거부합니다. 이는 최근 업데이트이므로 이 문서의 예제를 실행하려면 최신 Node 런타임(v>22)이 필요합니다.

기존 JavaScript Promise 메서드와 새로운 JavaScript Promise 메서드 비교

기능적으로 동일한 다음 두 코드 덩어리에서 Promise를 해결하거나 거부하는 메서드를 할당하는 기존 접근 방식과 새로운 접근 방식을 비교할 수 있습니다.

let resolve, reject;

const promise = new Promise((res, rej) => {
  resolve = res;
  reject = rej;
});

Math.random() > 0.5 ? resolve("ok") : reject("not ok");

위 코드에서 Promise의 가장 전통적인 사용법을 볼 수 있습니다. 새 Promise 객체를 인스턴스화한 다음 생성자에서 두 가지 함수인 해결(Resolve)과 거부(Reject)를 할당해야 합니다. 필요합니다.

다음 코드 조각에서는 동일한 코드 덩어리가 새로운 Promise.withResolvers() 메서드를 사용하여 다시 작성되었으며 더 단순해 보입니다.

const { promise, resolve, reject } = Promise.withResolvers();

Math.random() > 0.5 ? resolve("ok") : reject("not ok");

여기서 새로운 접근 방식이 어떻게 작동하는지 확인할 수 있습니다. .then() 메서드와 두 함수인 해결 및 거부를 호출할 수 있는 Promise를 반환합니다.

Promise에 대한 전통적인 접근 방식은 생성 및 이벤트 처리 논리를 단일 함수 내에 캡슐화합니다. 이는 여러 조건이나 코드의 다른 부분이 Promise를 해결하거나 거부해야 하는 경우 제한될 수 있습니다.

반대로 Promise.withResolvers()는 Promise 생성을 해결 논리에서 분리하여 더 큰 유연성을 제공하므로 복잡한 조건이나 여러 이벤트를 관리하는 데 적합합니다. 그러나 간단한 사용 사례의 경우 표준 약속 패턴에 익숙한 사용자에게는 기존 방법이 더 간단하고 친숙할 수 있습니다.

실제 예: API 호출

이제 보다 현실적인 예에서 새로운 접근 방식을 테스트할 수 있습니다. 아래 코드에서 API 호출의 간단한 예를 볼 수 있습니다.

function fetchData(url) {
    return new Promise((resolve, reject) => {
        fetch(url)
            .then(response => {
                // Check if the response is okay (status 200-299)
                if (response.ok) {
                    return response.json(); // Parse JSON if response is okay
                } else {
                    // Reject the promise if the response is not okay
                    reject(new Error('API Invocation failed'));
                }
            })
            .then(data => {
                // Resolve the promise with the data
                resolve(data);
            })
            .catch(error => {
                // Catch and reject the promise if there is a network error
                reject(error);
            });
    });
}

// Example usage
const apiURL = '';

fetchData(apiURL)
    .then(data => {
        // Handle the resolved data
        console.log('Data received:', data);
    })
    .catch(error => {
        // Handle any errors that occurred
        console.error('Error occurred:', error);
    });

fetchData 함수는 URL을 가져와서 fetch API를 사용하여 API 호출을 처리하는 Promise를 반환하도록 설계되었습니다. 응답 상태가 성공을 나타내는 200-299 범위 내에 있는지 확인하여 응답을 처리합니다.

성공하면 응답이 JSON으로 구문 분석되고 결과 데이터로 약속이 해결됩니다. 응답이 성공하지 못하면 적절한 오류 메시지와 함께 Promise가 거부됩니다. 또한 이 함수에는 네트워크 오류를 포착하는 오류 처리가 포함되어 있으며, 그러한 오류가 발생하면 Promise를 거부합니다.

이 예에서는 이 함수를 사용하는 방법을 보여 주며, .then() 블록으로 확인된 데이터를 관리하고 .catch() 블록을 사용하여 오류를 처리하는 방법을 보여줌으로써 성공적인 데이터 검색과 오류가 모두 적절하게 관리되도록 보장합니다.

아래 코드에서는 새로운 Promise.withResolvers() 메서드를 사용하여 fetchData() 함수를 다시 작성했습니다.

function fetchData(url) {
    const { promise, resolve, reject } = Promise.withResolvers();

    fetch(url)
        .then(response => {
            // Check if the response is okay (status 200-299)
            if (response.ok) {
                return response.json(); // Parse JSON if response is okay
            } else {
                // Reject the promise if the response is not okay
                reject(new Error('API Invocation failed'));
            }
        })
        .then(data => {
            // Resolve the promise with the data
            resolve(data);
        })
        .catch(error => {
            // Catch and reject the promise if there is a network error
            reject(error);
        });

    return promise;
}

보시다시피, 위의 코드는 더 읽기 쉽고 Promise 개체의 역할은 명확합니다. fetchData 함수는 성공적으로 해결되거나 실패할 Promise를 반환하고 각 경우에 적절한 메소드를 호출합니다. . api.invocation.{old|new}.js.

라는 저장소에서 위의 코드를 찾을 수 있습니다.

약속 취소

다음 코드는 Promise 취소 메소드를 구현하는 방법을 살펴봅니다. 아시다시피 JavaScript에서는 Promise를 취소할 수 없습니다. Promise는 비동기 작업의 결과를 나타내며, 생성된 후에는 취소할 수 있는 기본 제공 메커니즘 없이 해결 또는 거부하도록 설계되었습니다.

이 제한은 Promise에 정의된 상태 전환 프로세스가 있기 때문에 발생합니다. 보류 중으로 시작하고 일단 해결되면 상태를 변경할 수 없습니다. 작업 자체를 제어하기보다는 작업 결과를 캡슐화하기 위한 것입니다. 즉, 기본 프로세스에 영향을 주거나 취소할 수 없습니다. 이 디자인 선택은 약속을 단순하게 유지하고 작업의 최종 결과를 나타내는 데 중점을 둡니다.

const cancellablePromise = () => {
    const { promise, resolve, reject } = Promise.withResolvers();

    promise.cancel = () => {
        reject("the promise got cancelled");
    };
    return promise;
};

위 코드에서 cancelablePromise라는 개체를 볼 수 있습니다. 이 개체는 보시다시피 단순히 거부 메서드 호출을 강제하는 추가 cancel() 메서드가 포함된 Promise입니다. 이것은 단지 구문상의 설탕일 뿐이며 JavaScript Promise를 취소하지는 않지만 더 명확한 코드를 작성하는 데 도움이 될 수 있습니다.

대체 접근 방식은 AbortController 및 AbortSignal을 사용하는 것입니다. 이는 기본 작업(예: HTTP 요청)에 연결되어 필요할 때 취소할 수 있습니다. 문서에서 AbortController 및 AbortSignal 접근 방식이 위 코드에서 구현한 것보다 더 표현력이 뛰어난 구현임을 알 수 있습니다. 일단 AbortSignal이 호출되면 Promise가 거부됩니다.

또 다른 접근 방식은 취소 기능을 포함하여 비동기 데이터 스트림에 대한 보다 정교한 제어인 Observable 패턴의 구현을 제공하는 RxJS와 같은 반응형 프로그래밍 라이브러리를 사용하는 것입니다.

Observable과 Promise의 비교

실제 사용 사례에 관해 말할 때, Promise는 API에서 데이터를 가져오는 것과 같은 단일 비동기 작업을 처리하는 데 매우 적합합니다. 대조적으로, Observable은 시간이 지남에 따라 여러 값이 방출될 수 있는 사용자 입력, WebSocket 이벤트 또는 HTTP 응답과 같은 데이터 스트림을 관리하는 데 이상적입니다.

Promise는 일단 시작되면 취소할 수 없지만 Observable은 스트림 구독을 취소하여 취소할 수 있다는 점을 이미 명확히 했습니다. 일반적인 아이디어는 Observable을 사용하면 객체와의 가능한 상호 작용에 대한 명시적인 구조를 갖는다는 것입니다:

  • Observable을 생성하면 모든 Observable이 이를 구독할 수 있습니다.
  • Observable은 작업을 수행하고 상태를 변경하고 이벤트를 방출합니다. 모든 관찰자는 업데이트를 받게 됩니다. 이것이 약속과의 주요 차이점입니다. Observer가 있는 한 Observable은 계속 이벤트를 방출할 수 있지만 Promise는 단 한 번만 해결될 수 있습니다.
  • Observer가 Observable의 이벤트에 관심이 없으면 구독을 취소하여 리소스를 확보할 수 있습니다.

이 내용은 아래 코드에 나와 있습니다.

import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  subscriber.complete();
});

const observer = observable.subscribe({
  next(x) { console.log('Received value:', x); },
  complete() { console.log('Observable completed'); }
});

observer.unsubscribe();

Observable은 세 개의 값을 반환하지만 Promise는 한 번만 해결할 수 있으므로 이 코드는 Promise로 다시 작성할 수 없습니다.

unsubscribe 메소드를 더 실험하기 위해 takeWhile() 메소드를 사용할 다른 Observer를 추가할 수 있습니다. 이를 통해 Observer는 값이 특정 조건과 일치할 때까지 기다리게 됩니다. 예를 들어 아래 코드에서는 값이 2:
가 아닌 동안 Observable에서 이벤트를 계속 수신합니다.

import { Observable, takeWhile } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next(1);
  subscriber.next(2);
  subscriber.next(3);
  subscriber.complete();
});

const observer1 = observable.subscribe({
  next(x) { console.log('Received by 1 value:', x); },
  complete() { console.log('Observable 1 completed'); }
});

const observer2 = observable.pipe(
  takeWhile(value => value != "2")
).subscribe(value => console.log('Received by 2 value:', value));

위 코드에서 관찰자1은 우리가 이미 본 것과 같습니다. 구독하고 Observable에서 모든 이벤트를 계속 수신합니다. 두 번째인 Observer2는 조건이 일치하는 동안 Observable로부터 요소를 수신합니다. 이 경우에는 값이 2와 다를 때를 의미합니다.

실행을 통해 두 가지 메커니즘이 어떻게 작동하는지 확인할 수 있습니다.

$ node observable.mjs
Received by 1 value: 1
Received by 1 value: 2
Received by 1 value: 3
Observable 1 completed
Received by 2 value: 1
$

결론

이 기사에서는 JavaScript에서 Promise를 할당하는 새로운 메커니즘을 조사하고 Promise가 완료되기 전에 취소할 수 있는 몇 가지 방법을 제시했습니다. 또한 Promise의 기능을 제공할 뿐만 아니라 이벤트의 다중 방출과 구독 취소를 위한 적절한 메커니즘을 허용하여 Promise를 확장하는 Observable 객체와 Promise를 비교했습니다.


LogRocket: 컨텍스트를 이해하여 JavaScript 오류를 더 쉽게 디버깅합니다.

코드 디버깅은 항상 지루한 작업입니다. 하지만 오류를 더 많이 이해할수록 오류를 수정하는 것이 더 쉬워집니다.

LogRocket을 사용하면 이러한 오류를 새롭고 독특한 방식으로 이해할 수 있습니다. 당사의 프런트엔드 모니터링 솔루션은 JavaScript 프런트엔드에 대한 사용자 참여를 추적하여 오류를 초래한 사용자의 행동을 정확하게 확인할 수 있는 기능을 제공합니다.

Mastering promise cancellation in JavaScript

LogRocket은 콘솔 로그, 페이지 로드 시간, 스택 추적, 헤더 본문을 통한 느린 네트워크 요청/응답, 브라우저 메타데이터 및 사용자 정의 로그를 기록합니다. JavaScript 코드의 영향을 이해하는 것은 결코 쉬운 일이 아닙니다!

무료로 사용해 보세요.

릴리스 선언문 이 글은 https://dev.to/logrocket/mastering-promise-cancellation-in-javascript-1eb7?1에서 복제됩니다. 침해 내용이 있는 경우, [email protected]으로 연락하여 삭제하시기 바랍니다.
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3