new Promise () 생성자 내부에서 async / await를 사용하는 것이 안티 패턴입니까?


92

async.eachLimit번에 최대 작업 수를 제어 하는 기능을 사용하고 있습니다.

const { eachLimit } = require("async");

function myFunction() {
 return new Promise(async (resolve, reject) => {
   eachLimit((await getAsyncArray), 500, (item, callback) => {
     // do other things that use native promises.
   }, (error) => {
     if (error) return reject(error);
     // resolve here passing the next value.
   });
 });
}

보시다시피 myFunction함수의 두 번째 콜백 내부의 값에 액세스 할 수 없기 때문에 함수를 비동기로 선언 할 수 없습니다 eachLimit.


"보시다시피 myFunction을 비동기로 선언 할 수 없습니다."--- 더 자세히 설명해 주시겠습니까?
zerkms

1
아, 그래 ... 미안. 한 번에 500 개 이상의 비동기 작업을 피하기 위해 async.eachLimit이 필요하기 때문에 생성자가 필요합니다. 텍스트 파일에서 데이터를 다운로드하고 추출 중이며 많은 비동기 작업을 피하고 싶습니다. 데이터를 추출한 후 데이터에 대한 Promise를 반환해야하며 async.eachLimit의 콜백에서이를 반환 할 수 없습니다. .

1. 기다림이 필요한 이유는 무엇입니까? 비동기는 이미 제어 흐름 메커니즘입니다. 2. 당신은 Node.js를 비동기-Q를 살펴 걸릴 내부에 약속 async.js를 사용하려면
slebetman

콜백 지옥을 피하고 무언가가 던져지면 외부 약속이 포착됩니다.

답변:


81

promise 생성자 실행기 함수 내에서 promise를 효과적으로 사용하고 있으므로 Promise 생성자 anti-pattern 입니다.

코드는 모든 오류를 안전하게 전파하지 않는 주요 위험의 좋은 예입니다. 거기에 이유 읽기 .

또한 async/ await를 사용하면 동일한 함정을 훨씬 더 놀랍게 만들 수 있습니다. 비교:

let p = new Promise(resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Catches it.

순진한 (잘못된) async동등 물 :

let p = new Promise(async resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Doesn't catch it!

브라우저의 웹 콘솔에서 마지막 콘솔을 찾으십시오.

첫 번째 는 Promise 생성자 실행기 함수의 즉각적인 예외가 새로 생성 된 promise를 편리하게 거부 하기 때문에 작동 합니다..then 사용자가 직접 수행).

두 번째는 async함수의 즉각적인 예외 함수 자체에서 반환 한 암시 적 약속을 거부 하기 때문에 작동하지 않습니다.async 입니다.

프라 미스 생성자 실행 함수의 반환 값이 사용되지 않았기 때문에 그것은 나쁜 소식입니다!

귀하의 코드

다음 myFunction과 같이 정의 할 수없는 이유는 없습니다 async.

async function myFunction() {
  let array = await getAsyncArray();
  return new Promise((resolve, reject) => {
    eachLimit(array, 500, (item, callback) => {
      // do other things that use native promises.
    }, error => {
      if (error) return reject(error);
      // resolve here passing the next value.
    });
  });
}

왜 오래된 동시성 제어 라이브러리를 사용 await합니까?


12
당신은 필요하지 않습니다 return await: return new Promise충분합니다.
lonesomeday

2
나는 공식적으로 답을 승인, 나는 정확히 :-) 같은 말한 것
BERGI

1
@celoxxx 여기를보세요 . 당신은 참으로 약속 async.js를 사용해서는 안
BERGI

1
@celoxxx 유형을 삭제하면 일반 js가됩니다. 다른 인터페이스 (노드 스타일 콜백 대 약속)가 너무 많은 마찰을 일으키고 불필요하고 복잡하고 오류가 발생하기 쉬운 코드로 이어지기 때문에 async.js를 사용해서는 안됩니다.
Bergi

1
동의합니다 ...하지만이 코드는 오래되었고, 이벤트 + async.js를 사용하도록 리팩토링 중입니다 (아직 비동기 제한을 제어하기 위해. 더 나은 방법을 알고 있다면 말씀해주세요).

16

나는 위에 주어진 답변에 동의하며, 때로는 약속 내부에 비동기를 갖는 것이 더 깔끔합니다. 특히 약속을 반환하는 여러 작업을 연결하고 then().then()지옥을 피하려는 경우 더욱 그렇습니다 . 그 상황에서 다음과 같은 것을 사용하는 것을 고려할 것입니다.

const operation1 = Promise.resolve(5)
const operation2 = Promise.resolve(15)
const publishResult = () => Promise.reject(`Can't publish`)

let p = new Promise((resolve, reject) => {
  (async () => {
    try {
      const op1 = await operation1;
      const op2 = await operation2;

      if (op2 == null) {
         throw new Error('Validation error');
      }

      const res = op1 + op2;
      const result = await publishResult(res);
      resolve(result)
    } catch (err) {
      reject(err)
    }
  })()
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e));
  1. Promise생성자에 전달 된 함수 는 비동기가 아니므로 linter에 오류가 표시되지 않습니다.
  2. 모든 비동기 함수는를 사용하여 순차적으로 호출 할 수 있습니다 await.
  3. 비동기 작업의 결과를 검증하기 위해 사용자 지정 오류를 추가 할 수 있습니다.
  4. 결국 오류가 잘 잡 힙니다.

단점은 비록 당신이 퍼팅을 기억해야한다는 것입니다 try/catch및에 부착 reject.


4
static getPosts(){
    return new Promise( (resolve, reject) =>{
        try {
            const res =  axios.get(url);
            const data = res.data;
            resolve(
                data.map(post => ({
                    ...post,
                    createdAt: new Date(post.createdAt)
                }))
            )
        } catch (err) {
            reject(err);                
        }
    })
}

await를 제거하면 async가이 문제를 해결합니다. Promise 객체를 적용했기 때문에 충분합니다.


따라서 귀하의 예에서 axios.get(url)마치 await axios.get(url)?
PrestonDocks
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.