js中async/await与Promise的区别
作者:接着奏乐接着舞。
基本概念
首先,我们需要明白async/await和Promise都是JavaScript中处理异步操作的API。
- Promise: 是一种代表了某个异步操作最终完成(或失败)及其结果值的对象。
 - async/await: 是基于Promise的语法糖,它允许我们以更同步的方式编写异步代码。
 
使用Promise
基本语法
Promise.all() 接受一个 Promise 数组作为参数,返回一个新的 Promise 实例。这个新 Promise 的行为表现为:
- 当所有传入的 Promises 都成功解决时,它会解决(resolve)为一个包含所有 Promises 结果的数组。
 - 如果任何一个 Promise 失败(即被拒绝),Promise.all() 返回的 Promise 会立即失败,并返回相应的错误。
 
在没有async/await之前,我们通常通过链式调用.then()和.catch()方法来处理Promise。例如,如果要按顺序执行两个异步操作,可能会这样写:
doSomethingAsync()
  .then(result => {
    console.log(result);
    return doSomethingElseAsync(result);
  })
  .then(newResult => {
    console.log(newResult);
  })
  .catch(error => {
    console.error('Something went wrong', error);
  });
这种方式可以有效地处理异步操作,但当涉及到多个异步操作时,代码可能会变得复杂和难以阅读,这通常被称为“回调地狱”。
并行 vs 串行
Promise.all() 的一个关键优势是它能够并行处理 Promises。这意味着所有 Promises 都是同时启动的,这与串行执行(一个接一个地执行)形成对比。并行执行可以显著提高程序的效率,特别是在处理多个独立任务时。
快速失败机制
Promise.all() 实现了快速失败机制,即如果其中一个 Promise 失败,则整个 Promise.all() 调用会立即失败。这种机制保证了一致的错误处理,但也意味着在某些场景下需要更谨慎地处理错误。
错误处理策略
由于快速失败的特性,使用 Promise.all() 时应该特别注意错误处理。例如,如果你正在从多个源加载重要数据,一个源的失败不应该阻碍其他数据的处理。这时,你可以在每个单独的 Promise 上使用 .catch() 方法来处理错误,确保每个 Promise 都不会抛出错误。
Promise.all([
  fetchUserInfo
(1).catch(err => ({ error: err.message })),
  fetchOrderHistory(1).catch(err => ({ error: err.message }))
])
.then(([userInfo, orders]) => {
  if (!userInfo.error) {
    console.log('用户信息:', userInfo);
  }
  if (!orders.error) {
    console.log('订单历史:', orders);
  }
})
.catch(error => {
  console.error('未预期的错误:', error);
});
在这个修改后的例子中,即使 fetchUserInfo 或 fetchOrderHistory 中的一个失败了,另一个的结果仍然会被处理。
实际应用场景
Promise.all() 的应用场景非常广泛,以下是一些具体的例子:
1. 资源加载
在网页开发中,你可能需要同时加载多个资源,如图片、JSON 数据和脚本文件。使用 Promise.all() 可以同时启动所有资源的加载,并在全部资源加载完成后执行后续操作。
let imageLoadPromise = loadImage('image.png');
let dataLoadPromise = fetchData('/data.json');
let scriptLoadPromise = loadScript('script.js');
Promise.all([imageLoadPromise, dataLoadPromise, scriptLoadPromise])
    .then(([image, data, script]) => {
        // 所有资源加载完成
    })
    .catch(error => {
        // 处理加载错误
    });
2. 数据库操作
在服务器端应用程序中,当你需要执行多个没有依赖的数据库查询时,Promise.all() 可以并行执行这些查询,提高查询效率。
let userQuery = db.query("SELECT * FROM users WHERE id = ?", [userId]);
let postsQuery = db.query("SELECT * FROM posts WHERE authorId = ?", [userId]);
Promise.all([userQuery, postsQuery])
    .then(([users, posts]) => {
        // 处理查询结果
    })
    .catch(error => {
        // 处理数据库错误
    });
3. API 聚合
在构建一个聚合多个 API 数据的服务时,Promise.all() 可以并行调用这些 API,并在所有调用都完成后聚合这些数据。
let weatherPromise = fetchWeather(cityId);
let newsPromise = fetchNews(topic);
Promise.all([weatherPromise, newsPromise])
    .then(([weather, news]) => {
        // 创建包含天气和新闻的聚合数据
    })
    .catch(error => {
        // 处理 API 调用错误
    });使用async/await
async/await是在ES2017中引入的,使得异步代码的阅读和编写更像是传统的同步代码。async关键字用于声明一个异步函数,而await关键字则用于等待一个Promise的解决(fulfill)或拒绝(reject)。
同样的操作,使用async/await可以这样写:
async function asyncFunction() {
  try {
    const result = await doSomethingAsync();
    console.log(result);
    const newResult = await doSomethingElseAsync(result);
    console.log(newResult);
  } catch (error) {
    console.error('Something went wrong', error);
  }
}
在这个示例中,await使得JavaScript运行时等待Promise的解决,并且暂停函数的执行,直到Promise被解决。如果Promise被拒绝,错误将被catch块捕获。
总结区别
- 语法清晰: 
async/await提供了一种更清晰、更直观的方式来处理异步操作。代码看起来更像是同步的,因此更易于理解和维护。 - 错误处理: 使用
async/await时,可以使用传统的try/catch语句进行错误处理,这对于很多开发者来说更加熟悉。 - 调试友好: 
async/await使得在异步代码中使用断点调试变得更加直观。 - 基于Promise: 
async/await是建立在Promise之上的,实质上它并没有替代Promise的功能,而是提供了一种更简洁的使用方式。 
需要注意的是,async/await并不是在所有情况下都替代Promise链。例如,在处理多个并行异步操作时,Promise.all()仍然是一个非常有用的选择。
到此这篇关于js中async/await与Promise的区别的文章就介绍到这了,更多相关js async/await与Promise内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
