JavaScript 中的 Promise 和 Async await。

2025-05-27

JavaScript 中的 Promise 和 Async await。

承诺:
想象一下你是一位顶级歌手,粉丝们日夜询问你即将推出的歌曲。

为了减轻他们的负担,你承诺歌曲发布后会发给他们。你给粉丝们一个列表。他们可以填写自己的电子邮件地址,这样当歌曲发布时,所有订阅者都能立即收到。即使发生意外,比如录音室发生火灾,导致你无法发布歌曲,他们仍然会收到通知。

这是我们在编程中经常遇到的一个现实生活中的类比:

  1. “生产代码”是指执行某些操作并耗费时间的代码。例如,一些通过网络加载数据的代码。这就是“歌手”。
  2. “消费代码”希望在“生产代码”准备好后立即获得其结果。许多函数可能需要该结果。这些就是“粉丝”。
  3. promise 是一个特殊的 JavaScript 对象,它将“生产代码”和“消费者代码”连接在一起。打个比方:promise 就是一个“订阅列表”。“生产代码”会花费所需的时间来生成承诺的结果,而“promise”会在结果准备就绪后将其提供给所有订阅代码。

Promises 是 ES6 的一项新功能。它是一种编写异步代码的方法。在处理多个异步操作时,Promises 非常易于管理,而回调可能会造成回调地狱,导致代码难以管理。

工作原理。

Promise对象有3种状态:

1.Pending:初始状态,在 Promise 成功或失败之前
2.Resolved:已完成的 Promise
3.Rejected:失败的 Promise

一步步创建并使用 Promise

首先,我们使用构造函数创建一个 Promise 对象:

const myPromise = new Promise();
Enter fullscreen mode Exit fullscreen mode

它需要两个参数,一个表示成功(解决),一个表示失败(拒绝):

const myPromise = new Promise((resolve, reject) => {  
    // condition
});
Enter fullscreen mode Exit fullscreen mode

最后,会有一个条件。如果满足条件,则 Promise 被解决,否则被拒绝:

const myPromise = new Promise((resolve, reject) => {  
    let condition;  

    if(condition is met) {    
        resolve('Promise is resolved successfully.');  
    } else {    
        reject('Promise is rejected');  
    }
});
Enter fullscreen mode Exit fullscreen mode

这样我们就创建了第一个 Promise。现在让我们来使用它。

对于已解决的承诺,则使用 then() 方法:

myPromise.then();
Enter fullscreen mode Exit fullscreen mode

在 Promise 被解析后,then() 方法会被调用。然后我们就可以决定如何处理这个被解析的 Promise。

例如,让我们将从 Promise 获得的消息记录到控制台:

myPromise.then((message) => {  
    console.log(message);
});
Enter fullscreen mode Exit fullscreen mode

catch() 用于已拒绝的 Promise:
然而,then() 方法仅适用于已解析的 Promise。如果 Promise 失败了怎么办?这时,我们需要使用 catch() 方法。

同样,我们附加 then() 方法。我们也可以在 then() 之后直接附加 catch() 方法:

例子,

myPromise.then((message) => { 
    console.log(message);
}).catch((message) => { 
    console.log(message);
});
Enter fullscreen mode Exit fullscreen mode
异步函数——让 Promise 更友好

ECMAScript 2017 中添加了 async 函数和 await 关键字。这些功能基本上充当
了 promise 之上的语法糖,使异步代码更易于编写和阅读。

Async 关键字

首先,我们有 async 关键字,将它放在函数声明前面,可以将其转换为异步函数。异步函数是一种知道如何预期 await 关键字调用异步代码的可能性的函数。

它们允许你像编写同步代码一样编写基于 Promise 的代码,但不会阻塞主线程。它们使你的异步代码不那么“聪明”,但可读性更高。

异步函数的工作原理如下:

async function myFirstAsyncFunction() {
  try {
    const fulfilledValue = await promise;
  }
  catch (rejectedValue) {
    // …
  }
}
Enter fullscreen mode Exit fullscreen mode

如果在函数定义前使用 async 关键字,则可以在函数内部使用 await。当您 await 一个 Promise 时,该函数会以非阻塞方式暂停,直到 Promise 完成。如果 Promise 完成,您将获得返回值。如果 Promise 拒绝,则会抛出被拒绝的值。

示例:记录获取操作
假设我们想要获取一个 URL,并将响应以文本形式记录下来。以下是使用 Promise 的示例:

function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    }).catch(err => {
      console.error('fetch failed', err);
    });
}
Enter fullscreen mode Exit fullscreen mode

使用异步函数可以实现同样的效果:

async function logFetch(url) {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}
Enter fullscreen mode Exit fullscreen mode

代码行数相同,但所有回调都消失了。这使得代码更易于阅读,特别是对于那些不太熟悉 Promise 的人来说。

添加错误处理

如果您想添加错误处理,您有几个选择。

您可以将同步的 try...catch 结构与 async/await 一起使用。此示例扩展了我们上面展示的代码的第一个版本:

async function myFetch() {
  try {
    let response = await fetch('coffee.jpg');

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    let myBlob = await response.blob();
    let objectURL = URL.createObjectURL(myBlob);
    let image = document.createElement('img');
    image.src = objectURL;
    document.body.appendChild(image);

  } catch(e) {
    console.log(e);
  }
}

myFetch();
Enter fullscreen mode Exit fullscreen mode

catch() {} 块传递了一个错误对象,我们称之为 e;我们现在可以将其记录到控制台,它将为我们提供一条详细的错误消息,显示在代码中抛出错误的位置。

如果您想使用我们上面展示的第二个(重构)版本的代码,那么您最好继续混合方法并将 .catch() 块链接到 .then() 调用的末尾,如下所示:

async function myFetch() {
  let response = await fetch('coffee.jpg');
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  return await response.blob();

}

myFetch().then((blob) => {
  let objectURL = URL.createObjectURL(blob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch((e) =>
  console.log(e)
);
Enter fullscreen mode Exit fullscreen mode

这是因为 .catch() 块会捕获异步函数调用和 Promise 链中发生的错误。如果你在这里使用了 try/catch 块,在调用 myFetch() 函数时,仍然可能会遇到未处理的错误。

参考:-developer.mozilla.org

文章来源:https://dev.to/santan47/promise-async-await-in-javascript-mlb
PREV
大 O 符号 - 简介
NEXT
8 个 React 性能技巧:让你的应用飞速运行!0. 设置 1. 避免使用 index 作为键 2. useEffect() 和 useCallback() 3. 记忆 React 组件 4. React.Fragments 5. 延迟加载 6. 渐进式图像加载 7. 使用 JS 动画替代 CSS 动画。8. 生产构建