programing

새로운 Promise() 생성자 내부에서 비동기/대기를 사용하는 것은 반패턴입니까?

goodsources 2023. 8. 29. 20:29
반응형

새로운 Promise() 생성자 내부에서 비동기/대기를 사용하는 것은 반패턴입니까?

사용 중입니다.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기능.

약속 생성자 실행자 함수 내에서 약속을 효과적으로 사용하고 있으므로 이것이 약속 생성자 안티패턴입니다.

코드는 모든 오류를 안전하게 전파하지 않는 주요 위험의 좋은 예입니다. 그런지 읽어보세요.

추가적으로, 의 사용.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 생성자 실행자 함수의 즉각적인 예외가 새로 구성된 약속을 편리하게 거부하기 때문에 작동합니다..then당신은 당신 자신입니다).

두 번째 것은 어떤 즉각적인 예외 때문에 작동하지 않습니다.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?

@Bergi가 제공한 피드백을 바탕으로 위에서 제시한 답변에 동의하며 차라리 다른 접근 방식을 선택하고 싶다는 점을 강조하고 싶습니다.

하지만 약속 안에 비동기식이 필요하다면 다음과 같은 것을 사용하는 것을 고려해 보겠습니다.

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생성자는 비동기가 아니므로 리터너가 오류를 표시하지 않습니다.
  2. 다음을 사용하여 모든 비동기 함수를 순차적으로 호출할 수 있습니다.await.
  3. 사용자 지정 오류를 추가하여 비동기 작업의 결과를 검증할 수 있습니다.
  4. 결국 오류가 잘 잡힙니다.

하지만 단점은 당신이 그것을 기억해야 한다는 것입니다.try/catch그리고 그것을 에 붙입니다.reject.

안티패턴은 안티패턴이라고 믿습니다.

비동기 약속 콜백 내의 던지기는 쉽게 잡을 수 있습니다.

(async () => {
    try {
        await new Promise (async (FULFILL, BREAK) => {
            try {
                throw null;
            }
            catch (BALL) {
                BREAK (BALL);
            }
        });
    }
    catch (BALL) {
        console.log ("(A) BALL CAUGHT", BALL);
        throw BALL;
    }
}) ().
catch (BALL => {
    console.log ("(B) BALL CAUGHT", BALL);
});

아니면 더 간단히 말하면,

(async () => {
    await new Promise (async (FULFILL, BREAK) => {
        try {
            throw null;
        }
        catch (BALL) {
            BREAK (BALL);
        }
    });
}) ().
catch (BALL => {
    console.log ("(B) BALL CAUGHT", BALL);
});

다른 답변을 읽어서 직접 깨달은 것은 아니지만, 중요한 것은 당신의 비동기 기능을 평가하여 약속으로 바꾸는 것입니다.

따라서 다음과 같은 방법을 사용하여 비동기 함수를 정의하면 다음과 같습니다.

let f = async () => {
    // ... You can use await, try/catch, throw syntax here (see answer of Vladyslav Zavalykhatko) .. 
};

다음을 사용하여 약속으로 전환:

let myPromise = f()

그런 다음 예를 들어 다음을 사용하여 is를 Promise로 조작할 수 있습니다.Promise.all([myPromise])...

물론 다음을 사용하여 하나의 라이너로 만들 수 있습니다.

(async () => { code with await })()
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);                
        }
    })
}

대기를 제거하면 비동기식으로 이 문제를 해결할 수 있습니다.Promise 개체를 적용했기 때문에 충분합니다.

언급URL : https://stackoverflow.com/questions/43036229/is-it-an-anti-pattern-to-use-async-await-inside-of-a-new-promise-constructor

반응형