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.