fulfilled, rejected, settled...혹시 Promise 용어 아세요?

14194 단어 JavaScript
Promise는 ES 2015에서 가져온 JavaScript의 언어 기능으로, 비동기 처리 객체를 나타냅니다.기본 사용법으로 우선fetch 등 비동기적으로 처리한 결과 프로미스 대상을 획득할 수 있다.이것then은 사용 방법 등을 통해 비동기 처리가 끝난 다음 처리에 로그인할 수 있다.또 ES2017에 추가된 async/await의 문법은 프로미스를 손쉽게 처리하기 위한 것이다.이는 JavaScript에서 고유한 개념이 아니라 C#에서는 Task, Rust에서는 Future 등으로 불린다.
JavaScript를 사용하는 많은 분들이 Promise를 많든 적든 사용해 보셨죠.그리고 저는 Promise가 성공과 실패라는 두 가지 결과가 있다는 것을 알고 싶습니다.이렇게 Promise는 상태가 있습니다.성공한 상태, 실패한 상태 외에도 처리해야 할 상태가 있다(성공한 상태인지 실패한 상태인지 알 수 없다).
이 글에서 프로미스 상태에 대한 용어를 설명하겠습니다.구체적으로 말하면 pending,fulfilled,rejected,settled,resolved를 처리한다.스타일북은 25.6 Promise Objects 처음에 쓴 내용이다.

배경: Promise.allSettled


갑자기 용어가 영어로 바뀌었지만 영어로 모두를 압도하려는 것은 아니다.이 글의 배경은Promise.allSettled이다.ECMAScript의 홍보원숭이 중 하나로, 2019년 1월 TC39 회의에서 스테이지2로 승격됐다.약 몇 년 후Promise.allSettled에 자바스크립트에 추가될 가능성이 크다는 것이다.
이것Promise.allSettledPromise.allPromise.race의 동반자다.모든 Promise 결과가 나올 때까지 매개변수에서 Promise 정렬을 수락합니다.Promise.all와는 다른 점은 납품된 Promise 중 하나가 실패한 경우에 있다.Promise.all는 이 경우 전체적으로 즉각 실패하고Promise.allSettled는 모든 프로미스의 결과가 나올 때까지 기다린다.자세한 동작은 설치 예를 보면 쉽게 알 수 있겠지.Promise.allSettled는 대체로 다음과 같이 실현할 수 있다(아직 하나의 절차이기 때문에 앞으로 규격에 변화가 발생할 수 있다).
Promise.allSettled 설치 예
Promise.allSettled = promises =>
  Promise.all(
    promises.map(p =>
      p.then(
        result => ({ status: "fulfilled", value: result }),
        error => ({ status: "rejected", reason: error })
      )
    )
  );
보시다시피 Promise.allSettled의 결과는 반드시 성공하고 대상의 배열을 되돌려줍니다.각 객체는 전달된 각 Promise의 결과를 나타내고 성공{ status: "fulfilled", value: 値 }하면 모양이 { status: "rejected", reason: エラーオブジェクト }인 객체로 돌아갑니다.
실제로 사용해 보세요.
Promise.allSettled 사용 예
Promise.allSettled([
  fetch('/'),
  fetch('https://qiita.com/'),
  fetch('https://nonexistend.invalid/'),
]).then(console.log);
시행되면 이렇게 된다https://qiita.com/.
Promise.all Settled에 Promise 3개를 준 결과 배열이 나왔습니다.위에서 말한 바와 같이 status 속성의 문자열을 통해 각각의 Promise가 성공했는지 실패했는지 판단할 수 있습니다. 이 중점은status 속성의'fulfilled'나'rejectd'문자열입니다.전자가 성공한 Promise의 결과, 후자가 실패한 Promise의 결과는 대응한다.이 프로미스all Settled를 사용하고 싶을 때, 어느 것이 어느 것인지 하나하나 조사하는 것은 정말 어리석다.적어도 이 두 용어를 기억해야 한다. 직관적인 설명 그럼 본제 용어에 대한 설명으로 들어갑니다.먼저 직관적인 설명을 하다. fulfilled, rejected, settled 방금 나온fulfilled와rejected는 이미 결과가 나온 Promise의 결과를 나타내는 용어다.fulfilled는 성공 상태이고, Rejected는 실패 상태입니다. 또한, Promise.all Settled의 이름에 사용되는 settled는fulfilled나rejected의 상태를 가리킨다.성공하든 실패하든 상관없이 어쨌든 이미 결과가 나온 프로미스를 지칭한 것이다.Promise.all Settled는 모든 Promise가 settled까지 기다린다는 뜻이다. pending 펜딩은 아직 결과가 없는 상태입니다.settled의 Promise가 아닌 pending이라는 뜻이다. 자세히 보면 위의 그림(Promisse.all Settled의 실행 예)의 Promise입니다.all Settled의 반환값은Promise {<pending>}이라고 쓰여 있습니다.Promise입니다.all Settled가 실행되는 순간이 아직 결과가 없다는 뜻이다. 분명히 모든 Promise는 pending,fulfilled,rejected 중 하나입니다.결과가 아직 나오지 않았는데 성공이냐 실패냐는 것이다. resolved 하지만 아직 해결되지 않은 용어가 하나 더 있다.그게 바로 Resolved입니다.상기 3개(settled 포함하면 4개)를 제외하고는 모든 Promise는 Resolved인지 아니면 Resolved(unresolved)인지 분류할 수 있다. 직관적으로 말하면 리솔브드의 프로미스는 이미 자신의 처리를 끝낸 프로미스다.필연적으로settled의Promise는resolved이지만pending의Promise는resolved와unresolved가 있다. 자신의 처리가 끝나지 않으면 결과를 결정할 수 없기 때문에 settled의 Promise가 Resolved라는 것을 안다.문제는 펜딩의 경우다.포인트는 프로미스가 자신의 결과를 다른 프로미스에게 위임할 수 있다는 점이다.A라는 프로미스가 결과를 B라는 프로미스에 의뢰하고 B가 펜딩까지 한 경우 A는 resolved지만 펜딩이다.전선으로 예를 봅시다. const sleep = duration => new Promise((resolve, reject) => setTimeout(resolve, duration)); const p1 = new Promise((resolve, reject) => { resolve(sleep(3000).then(()=> console.log('hi'))); }); 여기에 정의된 sleep은 매개변수가 지정한 시간 후에 Promise를 반환하는 함수입니다.팔로우프로미스 구조기를 사용해서 프로미스를 만들 때 구조기에 함수를 주는 거 알잖아.이 함수는 Resolve와 Reject를 받아들여 호출을 통해 Promise를 해결합니다.만약 수치를 Resolve에 건네주었다면 이 값은 Promise의 결과(성공)였지만 위의 예와 같이 Resolve에는 또 다른 Promise(이번은sleep(3000)가 있었다.then(()=> console.log('hi'))는 당신에게 맡길 수 있습니다.부탁입니다. 즉, 슬립(3000).then(()=> console.log('hi')가fulfilled로 변하는 동시에 p1도fulfilld로 변한다.이번에는 p1이fulfilld로 바뀐 지 3초 뒤.p1은 제작과 동시에 Resolved가 된다.당장 다른 프로미스에게 결과를 넘기기 때문이다.하지만 의뢰한 프로미스는 3초 뒤 펜딩이었고, p1도 마찬가지로 3초 뒤 펜딩이었기 때문이다.3초 후 의뢰인의 프로미스는fulfilled로 변하는 동시에 p1도fulfilled로 변한다. 한편 슬립(3000)은 3초 후까지의 unresolved다.왜 그랬을까, 리소스가 호출되기 전까지는 결과를 결정할 수 없고, 의뢰도 할 수 없기 때문이다.알다시피 Promise 구조기를 사용하여 Promise를 만들 때, Resolve나 Reject가 호출되기 전에는 unresolved 상태이고, 부르면 Resolved (pending이나settled일 수도 있습니다) 가 됩니다. 정의 보기여기에 설명된 용어를 말하자면, 첫머리에도 언급하였다.ECMAScript 규격서에 정의가 있다.
Any Promise object is in one of three mutually exclusive states: fulfilled, rejected, and pending:
A promise p is fulfilled if p.then(f, r) will immediately enqueue a Job to call the function f .
A promise p is rejected if p.then(f, r) will immediately enqueue a Job to call the function r .
A promise is pending if it is neither fulfilled nor rejected.
A promise is said to be settled if it is not pending, i.e. if it is either fulfilled or rejected.
A promise is resolved if it is settled or if it has been “locked in” to match the state of another promise. Attempting to resolve or reject a resolved promise has no effect. A promise is unresolved if it is not resolved. An unresolved promise is always in the pending state. A resolved promise may be pending, fulfilled or rejected.
대체로 다음과 같은 정의다.
  • p.then(f, r) 즉시 호출f 작업p을 등록하면fulfilled입니다.
  • p.then(f, r)가 바로 호출r의 작업p을 등록하면rejectd입니다.

  • fulfilled도 아니고 rejected도 아닌 Promise는 pending입니다.

  • pending이 아닌 Promise는 settled입니다.

  • settled의 Promise는 Resolved입니다.또 다른 Promisse와 상태가 일치하도록'고정'된 Promisse도 Resolved이다.
  • 특히fulfilled와rejected의 정의가 특징이다.'즉시 등록 호출 f 의 임무' 는 복잡한 개념이지만, '로그인 임무' 라는 말로는 f 동기화할 수 없다고 상상할 수 있다.이 일은 아래의 예를 실행하면 알 수 있다.
    Promise.resolve(3).then(console.log);
    console.log('hi');
    
    이 작업을 수행한 후
    hi
    3
    
    이런 순서로 로그를 표시합니다.Promise.resolve(3)fulfilled Proomise로 돌아왔기 때문에 호출then하고 호출console.log(3)하는 작업은 바로 등록됩니다.하지만 그 작업은 동기화되지 않았기 때문에 다음 문장console.log('hi') 다음에.현재 집행이 끝나면 임무로 등록된console.log(3).
    이게 얼마나 빠른지 말하자면 setTimeout(fn, 0) 등보다 빠르다.
    /*
     * 3
     * hi
     * の順番で表示される
     */
    Promise.resolve(3).then(console.log);
    setTimeout(()=> console.log('hi'), 0);
    
    비동기적으로 실행되는 작업 중에도 즉시 작업을 등록하면 대기 타이머를 중단할 수 있습니다.금방, 금방.
    /*
     * 3
     * 5
     * hi
     * の順番で表示される
     */
    Promise.resolve(3).then(v=> {
      Promise.resolve(5).then(console.log);
      console.log(v);
    });
    setTimeout(()=> console.log('hi'), 0);
    
    또 설명서에는 프로미스 대상이fulfilled, rejected, pending의 어떤 상태인지에 대한 정보를 [Promiise State] 내부 틈새규격서 25.6.6 Properties of Promise Instance에 저장했다.실제로 Promise.prototype.then의 정의를 보면 [Proomise State]가fulfilled나rejected라면 바로 이 함수를 이렇게 처리한다고 적혀 있다.
    마지막은 수수께끼.방금 생성된 다음 Promisep2,p3,p4 후의 상태를 분류하십시오.
    const p2 = new Promise(resolve => {
      resolve(Promise.resolve(123))
    });
    const p3 = new Promise(()=> {});
    const p4 = Promise.resolve(p3);
    
    답은: p2는fulfilled,p3는unresolved,p4는resolved와pending이다.

    총결산


    이 글은 Promise 상태와 관련된 용어인fulfilled,reject d,pending,settled,resolved를 소개했다.Promise.allSettled의 추가가 현실감을 가져온 지금, 이들 용어는 앞으로 더 가까워질 것으로 보인다.

    Q&A


  • Q. 왜 Promise.fulfill가 아닌 Promise.resolve일까?

  • A. Promise 대상자를 냈을 때fulfilled가 아닌rejected(가능)였기 때문이다.다른 한편, Promise.resolve의 반환값의Promise는 반드시 이미resolved가 될 것이다.

  • Q. settled 같은 게 좋다고 해도, 장시간 설명한 Resolved 같은 게 유용한가?

  • A.(시선 떼기)
  • 참조 링크

  • States and Fates
  • Promise.분류:allSettled
  • Promise.allSettled @ TC39 January 2019
  • 좋은 웹페이지 즐겨찾기