[javascript] Node.js 고유의 Promise.all 처리가 병렬 또는 순차적입니까?

문서 가 명확하지 않기 때문에이 점을 분명히하고 싶습니다 .

Q1은 : 되어 Promise.all(iterable)순차적으로 또는 병렬로 모두 약속 처리? 더 구체적으로 말하자면, 체인 약속을 실행하는 것과 같습니다.

p1.then(p2).then(p3).then(p4).then(p5)....

또는 모든 알고리즘의 몇 가지 다른 종류의 p1, p2, p3, p4, p5, 등 (병렬) 같은 시간에 호출되는 결과가 모두 해결 (또는 거부) 즉시 반환됩니다?

Q2 : 경우 Promise.all병렬 실행, 반복 가능 sequencially을 실행하는 편리한 방법은 무엇입니까?

참고 : Q 또는 Bluebird를 사용하고 싶지 않지만 모든 기본 ES6 사양을 사용하고 싶습니다.



답변

되어 Promise.all(iterable)모든 약속을 실행?

아니요, 약속은 “실행”될 수 없습니다. 그들이 될 때 그들은 그들의 작업을 시작 만들어 그들은 단지 결과를 나타냅니다 – – 그리고 당신은 심지어에게 전달하기 전에 병렬로 모든 것을 실행하고 있습니다 Promise.all.

Promise.all단지 않습니다 await를 여러 약속을. 어떤 순서로 해결되는지 또는 계산이 병렬로 실행되는지는 중요하지 않습니다.

iterable을 순차적으로 실행하는 편리한 방법이 있습니까?

이미 약속이 있다면 많은 것을 할 수 없지만 Promise.all([p1, p2, p3, …])(시퀀스 개념은 없습니다). 그러나 반복 가능한 비동기 함수가 있으면 실제로 순차적으로 실행할 수 있습니다. 기본적으로 당신은에서 얻을 필요가

[fn1, fn2, fn3, …]

fn1().then(fn2).then(fn3).then(…)

그리고 그 해결책은 다음을 사용하는 것입니다 Array::reduce.

iterable.reduce((p, fn) => p.then(fn), Promise.resolve())


답변

병행하여

await Promise.all(items.map(async item => { await fetchItem(item) }))

장점 : 더 빠릅니다. 하나라도 실패하더라도 모든 반복이 실행됩니다.

순서대로

for (let i = 0; i < items.length; i++) {
    await fetchItem(items[i])
}

장점 : 루프의 변수는 각 반복마다 공유 할 수 있습니다. 일반적인 명령형 동기 코드처럼 동작합니다.


답변

Bergis는 Array.reduce를 사용하여 올바른 길을 찾았습니다.

그러나 실제로 함수를 차례대로 실행하라는 약속을 반환하는 함수를 얻으려면 중첩을 더 추가해야했습니다.

내 실제 사용 사례는 다운 스트림 한계로 인해 차례로 순서대로 전송 해야하는 파일 배열입니다 …

여기 내가 끝내는 것이 있습니다.

getAllFiles().then( (files) => {
    return files.reduce((p, theFile) => {
        return p.then(() => {
            return transferFile(theFile); //function returns a promise
        });
    }, Promise.resolve()).then(()=>{
        console.log("All files transferred");
    });
}).catch((error)=>{
    console.log(error);
});

이전 답변에서 제안했듯이 다음을 사용하십시오.

getAllFiles().then( (files) => {
    return files.reduce((p, theFile) => {
        return p.then(transferFile(theFile));
    }, Promise.resolve()).then(()=>{
        console.log("All files transferred");
    });
}).catch((error)=>{
    console.log(error);
});

다른 파일을 시작하기 전에 전송이 완료 될 때까지 기다리지 않았으며 첫 번째 파일 전송이 시작되기 전에 “전송 된 모든 파일”텍스트도 표시되었습니다.

내가 뭘 잘못했는지 모르지만 나를 위해 일한 것을 나누고 싶었습니다.

편집 :이 게시물을 작성한 이후로 첫 번째 버전이 작동하지 않는 이유를 이해했습니다. then () 은 약속을 반환하는 함수를 기대합니다 . 따라서 괄호없이 함수 이름을 전달해야합니다! 이제 내 함수는 인수를 원하므로 인수를 사용하지 않는 익명 함수로 감싸 야합니다!


답변

@ Bergi의 대답을 자세히 설명하기 위해 (매우 간결하지만 이해하기 까다로운;)

이 코드는 배열의 각 항목을 실행하고 다음 ‘다음 체인’을 끝에 추가합니다.

function eachorder(prev,order) {
        return prev.then(function() {
          return get_order(order)
            .then(check_order)
            .then(update_order);
        });
    }
orderArray.reduce(eachorder,Promise.resolve());

이해가 되길 바랍니다.


답변

재귀 함수를 사용하여 비동기 함수를 사용하여 반복 가능한 iterable을 순차적으로 처리 할 수도 있습니다. 예를 들어 a비동기 함수로 처리 할 배열 이 주어지면 someAsyncFunction():

var a = [1, 2, 3, 4, 5, 6]

function someAsyncFunction(n) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("someAsyncFunction: ", n)
      resolve(n)
    }, Math.random() * 1500)
  })
}

//You can run each array sequentially with: 

function sequential(arr, index = 0) {
  if (index >= arr.length) return Promise.resolve()
  return someAsyncFunction(arr[index])
    .then(r => {
      console.log("got value: ", r)
      return sequential(arr, index + 1)
    })
}

sequential(a).then(() => console.log("done"))


답변

async await를 사용 하면 일련의 약속을 쉽게 순차적으로 실행할 수 있습니다.

let a = [promise1, promise2, promise3];

async function func() {
  for(let i=0; i<a.length; i++){
    await a[i]();
  }
}

func();

참고 : 위의 구현에서 약속이 거부되면 나머지는 실행되지 않습니다. 모든 약속을 실행하려면 await a[i]();내부 를 감싸십시오.try catch


답변

평행

이 예를 참조하십시오

const resolveAfterTimeout = async i => {
  return new Promise(resolve => {
    console.log("CALLED");
    setTimeout(() => {
      resolve("RESOLVED", i);
    }, 5000);
  });
};

const call = async () => {
  const res = await Promise.all([
    resolveAfterTimeout(1),
    resolveAfterTimeout(2),
    resolveAfterTimeout(3),
    resolveAfterTimeout(4),
    resolveAfterTimeout(5),
    resolveAfterTimeout(6)
  ]);
  console.log({ res });
};

call();

코드를 실행하면 6 개의 약속 모두에 대해 “CALLED”콘솔이 표시되고 해결 될 때 시간 초과 후 6 개의 응답마다 동시에 콘솔 링됩니다.