Heim  >  Artikel  >  Web-Frontend  >  Vermeiden Sie schnell Fallstricke und sprechen Sie über 5 häufige Fehler bei der Verwendung von Versprechen!

Vermeiden Sie schnell Fallstricke und sprechen Sie über 5 häufige Fehler bei der Verwendung von Versprechen!

青灯夜游
青灯夜游nach vorne
2021-12-08 10:22:191881Durchsuche

Dieser Artikel zeigt Ihnen 5 häufige Fehler bei der Verwendung von Versprechen, um Ihnen dabei zu helfen, Fallstricke schnell zu vermeiden. Ich hoffe, dass er für alle hilfreich ist!

Vermeiden Sie schnell Fallstricke und sprechen Sie über 5 häufige Fehler bei der Verwendung von Versprechen!

Promise bietet eine elegante Möglichkeit, asynchrone Vorgänge in JS abzuwickeln. Dies ist auch eine Lösung, um die „Rückrufhölle“ zu vermeiden. Allerdings verstehen nicht viele Entwickler, worum es geht. Daher neigen viele Menschen dazu, in der Praxis Fehler zu machen. [Verwandte Empfehlungen: Javascript-Lern-Tutorial]

In diesem Artikel stellen wir fünf häufige Fehler bei der Verwendung von Versprechen vor und hoffen, dass jeder diese Fehler vermeiden kann.

1. Vermeiden Sie die Promise-Hölle

Normalerweise wird Promise verwendet, um die Callback-Hölle zu vermeiden. Aber sie zu missbrauchen kann auch dazu führen, dass Versprechen zur Hölle werden.

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

Im obigen Beispiel haben wir drei verschachtelte Versprechen für userLogin, getararticle und showararticle. Auf diese Weise nimmt die Komplexität proportional zu den Codezeilen zu und der Code kann unleserlich werden. 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 中,使我们能够做到这一点?

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

Um diese Situation zu vermeiden, müssen wir den Code entschachteln, getArticle vom ersten then zurückgeben und ihn dann im zweiten then zurückgeben code> um damit umzugehen. 🎜
const createMyPromise = () => new Promise(resolve => {
  // HTTP request
  resolve(result);
});
🎜🎜🎜2. Verwenden Sie den Block 🎜🎜try/catch🎜🎜 in Promise🎜🎜🎜🎜Normalerweise verwenden wir den Block try/catch, um Fehler zu behandeln. Es wird jedoch nicht empfohlen, try/catch innerhalb eines Promise-Objekts zu verwenden. 🎜🎜Das liegt daran, dass bei Fehlern das Promise-Objekt automatisch innerhalb von catch behandelt wird. 🎜
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;);  
})();
🎜Im obigen Beispiel haben wir den try/catch-Block innerhalb des Promise verwendet. 🎜🎜Allerdings erkennt Promise selbst alle Fehler (auch Tippfehler) innerhalb seines Gültigkeitsbereichs, ohne dass ein try/catch-Block erforderlich ist. Es stellt sicher, dass alle während der Ausführung ausgelösten Ausnahmen abgefangen und in abgelehnte Versprechen umgewandelt werden. 🎜
(async () => {
    console.time(&#39;concurrent&#39;);
    await Promise.all([f1(), f2(), f3()]);
    console.timeEnd(&#39;concurrent&#39;); 
  })();
🎜🎜Hinweis: 🎜Es ist wichtig, .catch()-Blöcke innerhalb von Promise-Blöcken zu verwenden. Andernfalls kann es sein, dass Ihre Testfälle fehlschlagen und die Anwendung während der Produktionsphase abstürzt. 🎜🎜🎜🎜3. Verwenden Sie asynchrone Funktionen innerhalb von Promise-Blöcken. 🎜🎜🎜🎜Async/Await ist eine erweiterte Syntax für die Verarbeitung mehrerer Promises in synchronem Code. Wenn wir das Schlüsselwort async vor einer Funktionsdeklaration verwenden, wird ein Promise zurückgegeben. Mit dem Schlüsselwort await können wir den Code anhalten, bis das Promise, auf das wir warten, aufgelöst wird. oder ablehnen. 🎜🎜🎜Wenn Sie jedoch eine Async-Funktion in einen Promise-Block einfügen, treten einige Nebenwirkungen auf. 🎜🎜🎜Angenommen, wir möchten eine asynchrone Operation im Promise-Block ausführen, also verwenden wir das Schlüsselwort async, aber leider gibt unser Code einen Fehler aus. 🎜🎜Auf diese Weise können wir den Fehler nicht sofort beheben, selbst wenn Sie einen catch()-Block verwenden oder innerhalb eines try/catch-Blocks auf Ihr Promise warten. Bitte sehen Sie sich das Beispiel unten an. 🎜rrreee🎜Wenn ich innerhalb eines Promise-Blocks auf eine async-Funktion stoße, versuche ich, die async-Logik außerhalb des Promise-Blocks zu belassen, um sie synchron zu halten. Es funktioniert in 9 von 10 Fällen. 🎜🎜In einigen Fällen kann jedoch eine async-Funktion erforderlich sein. In diesem Fall bleibt keine andere Wahl, als es manuell mithilfe von try/catch-Blöcken zu verwalten. 🎜rrreee🎜🎜🎜4. Führen Sie den Promise-Block sofort nach dem Erstellen des Promise aus. 🎜🎜🎜🎜Was das Code-Snippet unten betrifft: Wenn wir das Code-Snippet dort platzieren, wo die HTTP-Anfrage aufgerufen wird, wird es sofort ausgeführt. 🎜rrreee🎜Der Grund dafür ist, dass dieser Code in einen Promise-Konstruktor eingeschlossen ist. Einige Leute denken jedoch möglicherweise, dass es erst nach der Ausführung der then-Methode von myPromise ausgelöst wird. 🎜🎜🎜Die Wahrheit ist jedoch nicht wahr. Im Gegensatz dazu wird beim Erstellen eines Promise der Rückruf sofort ausgeführt. 🎜🎜🎜Das bedeutet, dass die HTTP-Anfrage höchstwahrscheinlich bereits ausgeführt wird oder sich zumindest in einem geplanten Zustand befindet, wenn nach der Einrichtung von myPromise die folgende Zeile erreicht wird. 🎜🎜🎜Promises sind immer bestrebt, den Prozess umzusetzen. 🎜🎜🎜Aber was sollten Sie tun, wenn Sie Versprechen in Zukunft umsetzen möchten? Was ist, wenn ich jetzt keine HTTP-Anfrage stellen möchte? Ist in Promises ein magischer Mechanismus eingebaut, der uns dies ermöglicht? 🎜🎜Die Antwort ist die Verwendung von Funktionen. Funktionen sind ein zeitaufwändiger Mechanismus. Sie werden nur ausgeführt, wenn der Entwickler sie explizit mit () aufruft. Die bloße Definition einer Funktion bringt uns nicht weiter. Der effizienteste Weg, ein Versprechen „faul“ zu machen, besteht darin, es in eine Funktion zu packen 🎜
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

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

Das obige ist der detaillierte Inhalt vonVermeiden Sie schnell Fallstricke und sprechen Sie über 5 häufige Fehler bei der Verwendung von Versprechen!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen