[javascript] Promise.all : 해결 된 값의 순서

보면 MDN 것은 그것은처럼 보이는 values에 전달 then()Promise.all의 콜백 약속의 순서대로 값이 포함되어 있습니다. 예를 들면 다음과 같습니다.

var somePromises = [1, 2, 3, 4, 5].map(Promise.resolve);
return Promise.all(somePromises).then(function(results) {
  console.log(results) //  is [1, 2, 3, 4, 5] the guaranteed result?
});

누구 순서대로 나열 values해야하는지 사양을 인용 할 수 있습니까 ?

추신 : 그런 코드를 실행하는 것은 이것이 사실이지만 증거는 아니지만 사실이었던 것으로 나타났습니다. 우연의 일치 일 수 있습니다.



답변

순서가 유지 됩니다.

당신이 연결 사양에 따라, Promise.all(iterable)소요 iterable(인 개체를이 지원하는 Iterator인터페이스)를 매개 변수로 나중에 통화에 대한 PerformPromiseAll( iterator, constructor, resultCapability)그것으로, 이상 후자의 루프를 iterable사용하여 IteratorStep(iterator).
즉, 전달하는 iterable Promise.all()이 엄격하게 주문 된 경우 여전히 전달 된 주문이 계속됩니다.

해결은 Promise.all() Resolve각 해결 된 약속에 내부 [[Index]]슬롯 이있는 곳을 통해 구현되며 , 이는 원래 입력에서 약속의 색인을 표시합니다.


이 모든 것은 입력이 엄격하게 정렬되는 한 (예를 들어 배열) 출력이 입력으로 엄격하게 정렬됨을 의미합니다.

아래 바이올린 (ES6)에서이 동작을 확인할 수 있습니다.

// Used to display results
const write = msg => {
  document.body.appendChild(document.createElement('div')).innerHTML = msg;
};

// Different speed async operations
const slow = new Promise(resolve => {
  setTimeout(resolve, 200, 'slow');
});
const instant = 'instant';
const quick = new Promise(resolve => {
  setTimeout(resolve, 50, 'quick');
});

// The order is preserved regardless of what resolved first
Promise.all([slow, instant, quick]).then(responses => {
  responses.map(response => write(response));
});


답변

이전 답변에서 이미 언급했듯이 Promise.all모든 해결 된 값을 원래 약속의 입력 순서에 해당하는 배열로 집계합니다 (약속 집계 참조 ).

그러나 주문은 클라이언트 측에서만 유지된다는 점을 지적하고 싶습니다!

개발자에게는 약속이 순서대로 이행 된 것처럼 보이지만 실제로 약속은 다른 속도로 처리됩니다. 백엔드가 약속을 다른 순서로받을 수 있으므로 원격 백엔드로 작업 할 때 알아야합니다.

다음은 시간 초과를 사용하여 문제를 보여주는 예입니다.

Promise.all

const myPromises = [
  new Promise((resolve) => setTimeout(() => {resolve('A (slow)'); console.log('A (slow)')}, 1000)),
  new Promise((resolve) => setTimeout(() => {resolve('B (slower)'); console.log('B (slower)')}, 2000)),
  new Promise((resolve) => setTimeout(() => {resolve('C (fast)'); console.log('C (fast)')}, 10))
];

Promise.all(myPromises).then(console.log)

위에 표시된 코드에서 세 개의 약속 (A, B, C)이로 주어집니다 Promise.all. 세 가지 약속은 서로 다른 속도로 실행됩니다 (C가 가장 빠르고 B가 가장 느립니다). 그래서 console.log약속 의 진술이 다음과 같은 순서로 나타납니다.

C (fast)
A (slow)
B (slower)

약속이 AJAX 호출 인 경우 원격 백엔드는이 값을이 순서대로받습니다. 그러나 클라이언트 쪽에서 Promise.all는 결과가 myPromises어레이 의 원래 위치에 따라 정렬되도록합니다 . 따라서 최종 결과는 다음과 같습니다.

['A (slow)', 'B (slower)', 'C (fast)']

약속의 실제 실행도 보장하려면 약속 대기열과 같은 개념이 필요합니다. 다음은 p-queue 를 사용하는 예입니다 (주의 : 모든 약속을 함수로 묶어야합니다).

순차 약속 대기열

const PQueue = require('p-queue');
const queue = new PQueue({concurrency: 1});

// Thunked Promises:
const myPromises = [
  () => new Promise((resolve) => setTimeout(() => {
    resolve('A (slow)');
    console.log('A (slow)');
  }, 1000)),
  () => new Promise((resolve) => setTimeout(() => {
    resolve('B (slower)');
    console.log('B (slower)');
  }, 2000)),
  () => new Promise((resolve) => setTimeout(() => {
    resolve('C (fast)');
    console.log('C (fast)');
  }, 10))
];

queue.addAll(myPromises).then(console.log);

결과

A (slow)
B (slower)
C (fast)

['A (slow)', 'B (slower)', 'C (fast)']


답변

예,의 값 results은와 순서가 같습니다 promises.

ES6 사양을Promise.all 인용 할 수도 있지만 사용 된 반복자 API 및 일반 약속 생성자로 인해 다소 복잡합니다. 그러나 각 리졸버 콜백에는 [[index]]약속 배열 반복에서 생성되고 결과 배열의 값을 설정하는 데 사용되는 속성이 있습니다.


답변