[javascript] 단지 콜백을 약속하지 않습니까?

몇 년 동안 JavaScript를 개발해 왔으며 약속에 대한 소란을 전혀 이해하지 못합니다.

내가하는 일은 변화하는 것 같습니다.

api(function(result){
    api2(function(result2){
        api3(function(result3){
             // do work
        });
    });
});

어쨌든 비동기 와 같은 라이브러리를 사용할 수 있습니다 .

api().then(function(result){
     api2().then(function(result2){
          api3().then(function(result3){
               // do work
          });
     });
});

코드가 많고 읽기 쉽지 않습니다. 나는 여기서 아무것도 얻지 못했습니다. 갑자기 마술처럼 ‘평평하지 않습니다’. 사물을 약속으로 바꾸어야한다는 것은 말할 것도 없습니다.

그렇다면 약속에 대한 큰 소란은 무엇입니까?



답변

약속은 콜백이 아닙니다. 약속은 비동기 작업미래 결과를 나타냅니다 . 물론, 당신이하는 방식으로 글을 쓰면 거의 혜택을 얻지 못합니다. 그러나 사용하려는 방식으로 작성하면 동기 코드와 유사한 방식으로 비동기 코드를 작성할 수 있으며 훨씬 더 쉽게 수행 할 수 있습니다.

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
});

확실히 적은 코드는 아니지만 훨씬 더 읽기 쉽습니다.

그러나 이것은 끝이 아닙니다. 진정한 이점을 발견합시다 : 어떤 단계에서 오류를 확인하려면 어떻게해야합니까? 콜백으로 그것을하는 것은 지옥 일 것이지만 약속으로 케이크 한 조각입니다.

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
});

try { ... } catch블록 과 거의 동일합니다 .

더 나은 :

api().then(function(result){
    return api2();
}).then(function(result2){
    return api3();
}).then(function(result3){
     // do work
}).catch(function(error) {
     //handle any error that may occur before this point
}).then(function() {
     //do something whether there was an error or not
     //like hiding an spinner if you were performing an AJAX request.
});

그리고 더 나은 : 그 3 호출하는 경우에는 어떻게 api, api2, api3동시에 실행할 수 있습니다 (예를 들어, 그들은 AJAX 호출 인 경우) 그러나 당신이 세 가지를 기다릴 필요? 약속 없이는 일종의 카운터를 만들어야합니다. 약속과 함께 ES6 표기법을 사용하는 또 다른 케이크 조각이며 매우 깔끔합니다.

Promise.all([api(), api2(), api3()]).then(function(result) {
    //do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
    //handle the error. At least one of the promises rejected.
});

당신이 지금 새로운 관점에서 약속을 볼 수 있기를 바랍니다.


답변

예, 약속은 비동기 콜백입니다. 콜백으로 수행 할 수없는 작업을 수행 할 수 없으며 일반 콜백과 동일한 비동기 문제가 발생합니다.

그러나 약속은 다만 콜백 이상. 그것들은 매우 강력한 추상화이며 오류가 발생하기 쉬운 상용구로 깨끗하고 더 나은 기능 코드를 허용합니다.

그래서 주요 아이디어는 무엇입니까?

약속은 단일 (비동기) 계산 결과를 나타내는 객체입니다. 그들은 그 결과를 한 번만 해결 합니다 . 이것이 의미하는 것이 몇 가지 있습니다.

약속은 관찰자 패턴을 구현합니다.

  • 작업이 완료되기 전에 값을 사용할 콜백을 알 필요가 없습니다.
  • 콜백을 함수의 인수로 기대하지 return않고 Promise 객체를 쉽게 만들 수 있습니다 .
  • 약속은 값을 저장하며 언제든지 원할 때 투명하게 콜백을 추가 할 수 있습니다 . 결과가 나오면 호출됩니다. “투명도”는 약속이 있고 콜백을 추가 할 때 결과가 아직 도착했는지 여부에 상관없이 코드에 영향을 미치지 않음을 의미합니다. API와 계약이 동일하여 캐싱 / 메모 레이션을 크게 단순화합니다.
  • 여러 개의 콜백을 쉽게 추가 할 수 있습니다

약속은 체인 가능하다 ( 모나드 , 당신이 원하는 경우 ) :

  • 약속이 나타내는 값을 변환해야하는 경우 약속에 대해 변환 함수 를 맵핑 하고 변환 된 결과를 나타내는 새 약속을 다시 가져옵니다. 어떻게 든 사용하기 위해 동 기적으로 값을 얻을 수는 없지만 쉽게 들어 올릴 수 있습니다 약속 컨텍스트에서 변환을 . 상용구 콜백이 없습니다.
  • 두 개의 비동기 작업을 연결하려는 경우이 .then()방법을 사용할 수 있습니다 . 첫 번째 결과로 콜백을 호출하고 콜백이 리턴 한 약속의 결과에 대한 약속을 리턴합니다.

복잡한 소리? 코드 예제를위한 시간입니다.

var p1 = api1(); // returning a promise
var p3 = p1.then(function(api1Result) {
    var p2 = api2(); // returning a promise
    return p2; // The result of p2 …
}); // … becomes the result of p3

// So it does not make a difference whether you write
api1().then(function(api1Result) {
    return api2().then(console.log)
})
// or the flattened version
api1().then(function(api1Result) {
    return api2();
}).then(console.log)

평탄화는 마술처럼 나오지 않지만 쉽게 할 수 있습니다. 많이 중첩 된 예제의 경우 (거의) 동등한 것은

api1().then(api2).then(api3).then(/* do-work-callback */);

이러한 메소드의 코드를 이해하면 이해하는 데 도움이 될 것입니다. 여기 몇 줄로 된 가장 기본적인 promise lib가 있습니다 .

약속에 대한 큰 소란은 무엇입니까?

Promise 추상화는 기능의 구성 성을 훨씬 향상시킵니다. 예를 들어, then체인 옆에 있는 all함수는 여러 병렬 대기 약속의 결합 결과에 대한 약속을 만듭니다.

마지막으로 약속에는 통합 오류 처리가 제공됩니다. 계산의 결과는 약속이 가치 로 이행 되거나 이유로 거부 되는 것일 수 있습니다 . 모든 컴포지션 함수는 이것을 자동으로 처리하고 약속 체인에서 오류를 전파하므로 일반 콜백 구현과 달리 어디서나 명시 적으로 신경 쓰지 않아도됩니다. 결국, 발생한 모든 예외에 대해 전용 오류 콜백을 추가 할 수 있습니다.

사물을 약속으로 바꾸어야한다는 것은 말할 것도 없습니다.

실제로 좋은 약속 라이브러리를 사용하는 것은 쉽지 않습니다. 기존 콜백 API를 약속으로 변환하는 방법을 참조하십시오 .


답변

ES6 화살표 기능 약속과 함께 이미 설립 답변뿐만 아니라 겸손하게 빛나는 작은 파란 난쟁이에서 설정 바로 적색 거성으로. 그것은 초신성으로 무너질 것입니다.

api().then(result => api2()).then(result2 => api3()).then(result3 => console.log(result3))

으로 oligofren는 지적 API 호출 사이의 인수없이 모든에서 익명 래퍼 함수가 필요하지 않습니다 :

api().then(api2).then(api3).then(r3 => console.log(r3))

마지막으로, 엄청난 블랙홀 수준에 도달하려면 약속을 기다릴 수 있습니다.

async function callApis() {
    let api1Result = await api();
    let api2Result = await api2(api1Result);
    let api3Result = await api3(api2Result);

    return api3Result;
}


답변

위의 멋진 답변 외에도 2 점이 더 추가 될 수 있습니다.

1. 시맨틱 차이 :

약속은 이미 창조되었을 때 해결 될 수 있습니다. 이것은 사건이 아닌 조건을 보증 한다는 것을 의미 합니다 . 이미 해결 된 경우 전달 된 해결 된 함수는 여전히 호출됩니다.

반대로 콜백 은 이벤트를 처리합니다. 따라서 콜백이 등록되기 전에 관심있는 이벤트가 발생한 경우 콜백이 호출되지 않습니다.

2. 제어 역전

콜백 에는 제어 역전이 포함됩니다. API에 콜백 함수를 등록하면 Javascript 런타임은 콜백 함수를 저장하고 실행할 준비가되면 이벤트 루프에서 호출합니다.

설명 은 Javascript 이벤트 루프 를 참조하십시오 .

Promises를 사용하면 제어는 호출 프로그램에 상주합니다. promise 객체를 저장하면 언제든지 .then () 메서드를 호출 할 수 있습니다 .


답변

다른 답변 외에도 ES2015 구문은 약속과 매끄럽게 혼합되어 더 많은 상용구 코드를 줄입니다.

// Sequentially:
api1()
  .then(r1 => api2(r1))
  .then(r2 => api3(r2))
  .then(r3 => {
      // Done
  });

// Parallel:
Promise.all([
    api1(),
    api2(),
    api3()
]).then(([r1, r2, r3]) => {
    // Done
});


답변

약속은 콜백이 아니며 비동기 프로그래밍을 촉진하는 프로그래밍 관용구입니다. 약속을 반환하는 코 루틴이나 생성기를 사용하여 비동기 / 대기 스타일의 프로그래밍을 사용하는 것은 이러한 관용구 중 세 번째로 간주 될 수 있습니다. 다른 프로그래밍 언어 (Javascript 포함)에서이 관용구를 비교 한 내용은 다음과 같습니다. https://github.com/KjellSchubert/promise-future-task


답변

아뇨

콜백 은 단순히 다른 함수의 실행이 완료된 후 호출되고 실행되는 JavaScript 의 함수입니다. 어떻게 되나요?

실제로 JavaScript에서 함수 자체는 객체로 간주되므로 다른 모든 객체와 마찬가지로 함수조차도 다른 함수에 대한 인수로 보낼 수 있습니다 . 가장 일반적이고 일반적인 유스 케이스는 JavaScript의 setTimeout () 함수입니다.

약속 은 콜백과 동일한 작업을 수행하는 것과 비교하여 비동기 코드를 처리하고 구조화하는 훨씬 더 즉흥적 인 접근 방식입니다.

Promise는 생성자 함수에서 두 개의 콜백 (resolve 및 reject)을받습니다. 약속 내부의 이러한 콜백은 오류 처리 및 성공 사례에 대한 세밀한 제어를 제공합니다. 확인 콜백은 약속 실행이 성공적으로 수행되었을 때 사용되며 거부 콜백은 오류 사례를 처리하는 데 사용됩니다.