>웹 프론트엔드 >JS 튜토리얼 >신속하게 함정을 피하고 Promise 사용 시 흔히 발생하는 5가지 실수에 대해 이야기해 보세요!

신속하게 함정을 피하고 Promise 사용 시 흔히 발생하는 5가지 실수에 대해 이야기해 보세요!

青灯夜游
青灯夜游앞으로
2021-12-08 10:22:191892검색

이 글에서는 Promise를 사용할 때 흔히 발생하는 5가지 실수를 공유하여 모든 사람에게 도움이 되기를 바랍니다.

신속하게 함정을 피하고 Promise 사용 시 흔히 발생하는 5가지 실수에 대해 이야기해 보세요!

Promise는 JS에서 비동기 작업을 처리하는 우아한 방법을 제공합니다. 이는 '콜백 지옥'을 피하기 위한 해결책이기도 하다. 그러나 관련 내용을 이해하는 개발자는 많지 않습니다. 그러므로 많은 사람들이 실제로 실수를 하는 경향이 있습니다. [관련 권장사항: javascript 학습 튜토리얼]

이 글에서는 Promise를 사용할 때 흔히 저지르는 5가지 실수를 소개하고, 모두가 이러한 실수를 피할 수 있기를 바랍니다.

1. Promise Hell을 피하세요

보통 Promise는 콜백 지옥을 피하기 위해 사용됩니다. 그러나 이를 남용하면 약속이 지옥이 될 수도 있습니다.

userLogin('user').then(function(user){
    getArticle(user).then(function(articles){
        showArticle(articles).then(function(){
            //Your code goes here...
        });
    });
});

위 예에는 userLogin, getararticleshowararticle에 대한 세 가지 중첩된 약속이 있습니다. 이렇게 하면 코드 줄에 비례하여 복잡성이 증가하여 읽을 수 없게 될 수 있습니다. userLogingetararticleshowararticle 嵌套了三个promise。这样复杂性将按代码行比例增长,它可能变得不可读。

为了避免这种情况,我们需要解除代码的嵌套,从第一个 then 中返回 getArticle,然后在第二个 then 中处理它。

userLogin('user')
  .then(getArticle)
  .then(showArticle)
  .then(function(){
       //Your code goes here...
});

2. 在 Promise 中使用 <span style="font-size: 18px;">try/catch</span>

通常情况下,我们使用 try/catch 块来处理错误。然而,不建议在 Promise 对象中使用try/catch

这是因为如果有任何错误,Promise对象会在 catch 内自动处理。

ew Promise((resolve, reject) => {
  try {
    const data = doThis();
    // do something
    resolve();
  } catch (e) {
    reject(e);
  }
})
  .then(data => console.log(data))
  .catch(error => console.log(error));

在上面的例子中,我们在Promise 内使用了 try/catch 块。

但是,Promise本身会在其作用域内捕捉所有的错误(甚至是打字错误),而不需要 try/catch块。它确保在执行过程中抛出的所有异常都被获取并转换为被拒绝的 Promise。

new Promise((resolve, reject) => {
  const data = doThis();
  // do something
  resolve()
})
  .then(data => console.log(data))
  .catch(error => console.log(error));

注意:在 Promise 块中使用 .catch() 块是至关重要的。否则,你的测试案例可能会失败,而且应用程序在生产阶段可能会崩溃。

3. 在 Promise 块内使用异步函数

Async/Await 是一种更高级的语法,用于处理同步代码中的多个Promise。当我们在一个函数声明前使用 async 关键字时,它会返回一个 Promise,我们可以使用 await 关键字来停止代码,直到我们正在等待的Promise解决或拒绝。

但是,当你把一个 Async 函数放在一个 Promise 块里面时,会有一些副作用。

假设我们想在Promise 块中做一个异步操作,所以使用了 async 关键字,但,不巧的是我们的代码抛出了一个错误。

这样,即使使用 catch() 块或在 try/catch 块内等待你的Promise,我们也不能立即处理这个错误。请看下面的例子。

// 此代码无法处理错误
new Promise(async () => {
  throw new Error(&#39;message&#39;);
}).catch(e => console.log(e.message));

(async () => {
  try {
    await new Promise(async () => {
      throw new Error(&#39;message&#39;);
    });
  } catch (e) {
    console.log(e.message);
  }
})();

当我在Promise块内遇到 async 函数时,我试图将 async 逻辑保持在 Promise 块之外,以保持其同步性。10次中有9次都能成功。

然而,在某些情况下,可能需要一个 async 函数。在这种情况下,也别无选择,只能用try/catch 块来手动管理。

new Promise(async (resolve, reject) => {
  try {
    throw new Error(&#39;message&#39;);
  } catch (error) {
    reject(error);
  }
}).catch(e => console.log(e.message));


//using async/await
(async () => {
  try {
    await new Promise(async (resolve, reject) => {
      try {
        throw new Error(&#39;message&#39;);
      } catch (error) {
        reject(error);
      }
    });
  } catch (e) {
    console.log(e.message);
  }
})();

4.在创建 Promise 后立即执行 Promise 块

至于下面的代码片断,如果我们把代码片断放在调用HTTP请求的地方,它就会被立即执行。

const myPromise = new Promise(resolve => {
  // code to make HTTP request
  resolve(result);
});

原因是这段代码被包裹在一个Promise构造函数中。然而,有些人可能会认为只有在执行myPromisethen方法之后才被触发。

然而,真相并非如此。相反,当一个Promise被创建时,回调被立即执行。

这意味着在建立 myPromise 之后到达下面一行时,HTTP请求很可能已经在运行,或者至少处于调度状态。

Promises  总是急于执行过程。

但是,如果希望以后再执行 Promises,应该怎么做?如果现在不想发出HTTP请求怎么办?是否有什么神奇的机制内置于 Promises 中,使我们能够做到这一点?

答案就是使用函数。函数是一种耗时的机制。只有当开发者明确地用 ()

이 상황을 방지하려면 코드 중첩을 해제하고 첫 번째 then에서 getArticle을 반환한 다음 두 번째 then에서 반환해야 합니다. code>를 처리합니다. 🎜
const createMyPromise = () => new Promise(resolve => {
  // HTTP request
  resolve(result);
});
🎜🎜🎜2. Promise🎜🎜🎜🎜에서 🎜🎜try/catch🎜🎜 블록을 사용합니다. 일반적으로 오류를 처리하려면 try/catch 블록을 사용합니다. 그러나 Promise 객체 내에서 try/catch를 사용하는 것은 권장되지 않습니다. 🎜🎜오류가 있으면 Promise 객체가 catch 내에서 자동으로 처리되기 때문입니다. 🎜
const { promisify } = require(&#39;util&#39;);
const sleep = promisify(setTimeout);

async function f1() {
  await sleep(1000);
}

async function f2() {
  await sleep(2000);
}

async function f3() {
  await sleep(3000);
}


(async () => {
  console.time(&#39;sequential&#39;);
  await f1();
  await f2();
  await f3();
  console.timeEnd(&#39;sequential&#39;);  
})();
🎜위 예에서는 Promise 내부에 try/catch 블록을 사용했습니다. 🎜🎜그러나 Promise 자체는 try/catch 블록 없이도 해당 범위 내의 모든 오류(심지어 오타)를 포착합니다. 실행 중에 발생한 모든 예외가 포착되어 거부된 약속으로 변환되도록 보장합니다. 🎜
(async () => {
    console.time(&#39;concurrent&#39;);
    await Promise.all([f1(), f2(), f3()]);
    console.timeEnd(&#39;concurrent&#39;); 
  })();
🎜🎜참고: 🎜Promise 블록 내에서 .catch() 블록을 사용하는 것이 중요합니다. 그렇지 않으면 테스트 사례가 실패하고 프로덕션 단계에서 애플리케이션이 충돌할 수 있습니다. 🎜🎜🎜🎜3. Promise 블록 내에서 비동기 함수 사용 🎜🎜🎜🎜Async/Await은 동기 코드에서 여러 Promise를 처리하기 위한 고급 구문입니다. 함수 선언 전에 async 키워드를 사용하면 Promise가 반환됩니다. await 키워드를 사용하면 기다리고 있는 Promise가 해결될 때까지 코드를 중지할 수 있습니다. 아니면 거절하세요. 🎜🎜🎜그러나 Promise 블록 안에 Async 함수를 넣으면 부작용이 발생합니다. 🎜🎜🎜Promise 블록에서 비동기 작업을 수행하려고 하여 async 키워드를 사용했지만 안타깝게도 코드에서 오류가 발생했다고 가정해 보겠습니다. 🎜🎜이렇게 하면 catch() 블록을 사용하거나 try/catch 블록 내에서 Promise를 기다리더라도 오류를 즉시 처리할 수 없습니다. 아래 예를 참조하십시오. 🎜rrreee🎜Promise 블록 내부에서 async 함수를 발견하면 Promise 블록 외부에 async 논리를 유지하여 동기화를 유지하려고 합니다. 10번 중 9번은 작동합니다. 🎜🎜단, 경우에 따라 async 기능이 필요할 수 있습니다. 이 경우에는 try/catch 블록을 이용해 수동으로 관리할 수밖에 없습니다. 🎜rrreee🎜🎜🎜4. Promise 생성 후 즉시 Promise 블록을 실행합니다🎜🎜🎜🎜아래 코드 스니펫은 HTTP 요청이 호출되는 곳에 코드 스니펫을 넣으면 즉시 실행됩니다. 🎜rrreee🎜이유는 이 코드가 Promise 생성자에 래핑되어 있기 때문입니다. 그러나 어떤 사람들은 myPromisethen 메서드를 실행한 후에만 트리거된다고 생각할 수도 있습니다. 🎜🎜🎜그러나 진실은 사실이 아닙니다. 반대로 Promise가 생성되면 콜백이 즉시 실행됩니다. 🎜🎜🎜이는 myPromise를 설정한 후 다음 줄에 도달할 때쯤이면 HTTP 요청이 이미 실행 중이거나 적어도 예약된 상태일 가능성이 높다는 의미입니다. 🎜🎜🎜약속은 항상 프로세스를 실행하기를 열망합니다. 🎜🎜🎜하지만 나중에 Promise를 실행하려면 어떻게 해야 할까요? 지금 HTTP 요청을 하고 싶지 않으면 어떻게 하나요? 이를 가능하게 하는 마법의 메커니즘이 Promise에 내장되어 있나요? 🎜🎜 정답은 기능을 활용하는 것입니다. 함수는 시간이 많이 걸리는 메커니즘입니다. 개발자가 ()를 사용하여 명시적으로 호출하는 경우에만 실행됩니다. 단순히 함수를 정의한다고 해서 아무 것도 얻을 수는 없습니다. 따라서 Promise를 게으르게 만드는 가장 효율적인 방법은 함수로 래핑하는 것입니다!
const createMyPromise = () => new Promise(resolve => {
  // HTTP request
  resolve(result);
});

对于HTTP请求,Promise 构造函数和回调函数只有在函数被执行时才会被调用。所以现在我们有一个懒惰的Promise,只有在我们需要的时候才会执行。

5. 不一定使用 Promise.all() 方法

如果你已经工作多年,应该已经知道我在说什么了。如果有许多彼此不相关的 Promise,我们可以同时处理它们。

Promise 是并发的,但如你一个一个地等待它们,会太费时间,Promise.all()可以节省很多时间。

记住,Promise.all() 是我们的朋友
const { promisify } = require(&#39;util&#39;);
const sleep = promisify(setTimeout);

async function f1() {
  await sleep(1000);
}

async function f2() {
  await sleep(2000);
}

async function f3() {
  await sleep(3000);
}


(async () => {
  console.time(&#39;sequential&#39;);
  await f1();
  await f2();
  await f3();
  console.timeEnd(&#39;sequential&#39;);  
})();

上述代码的执行时间约为 6 秒。但如果我们用 Promise.all() 代替它,将减少执行时间。

(async () => {
    console.time(&#39;concurrent&#39;);
    await Promise.all([f1(), f2(), f3()]);
    console.timeEnd(&#39;concurrent&#39;); 
  })();

总结

在这篇文章中,我们讨论了使用 Promise 时常犯的五个错误。然而,可能还有很多简单的问题需要仔细解决。

如果你还有更多相关的错误,欢迎留言一起讨论。

英文原文地址:https://blog.bitsrc.io/5-common-mistakes-in-using-promises-bfcc4d62657f

作者:Ravidu Perera

更多编程相关知识,请访问:编程入门!!

위 내용은 신속하게 함정을 피하고 Promise 사용 시 흔히 발생하는 5가지 실수에 대해 이야기해 보세요!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제