Js异步与Promise

异步的概念

异步(Asynchronous, async)是与同步(Synchronous, sync)相对的概念
在我们学习的传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系。
简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高
以上是关于异步的概念的解释,接下来我们通俗地解释一下异步:异步就是从主线程发射一个子线程来完成任务。

什么时候用异步编程

在前端编程中(甚至后端有时也是这样),我们在处理一些简短、快速的操作时,例如计算 1 + 1 的结果,往往在主线程中就可以完成。主线程作为一个线程,不能够同时接受多方面的请求。所以,当一个事件没有结束时,界面将无法处理其他请求。
现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。
为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。
为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

在JS中常用的异步编程方法有以下几种:

  1. 回调函数:使用回调函数可以让我们在异步操作完成后执行相应的操作。
function fetchData(callback) {
    
    
  // 模拟异步操作
  setTimeout(function() {
    
    
    const data = '这是从服务器获取的数据';
    callback(data);
  }, 2000);
}

// 调用 fetchData 函数,并传入回调函数来处理获取的数据
fetchData(function(data) {
    
    
  console.log(data); // 输出:这是从服务器获取的数据
});
  1. async/await:async/await是ES8中引入的一种语言特性,用于简化Promise的使用。
function fetchData() {
    
    
  return new Promise(function(resolve, reject) {
    
    
    // 模拟异步操作
    setTimeout(function() {
    
    
      const data = '这是从服务器获取的数据';
      resolve(data);
    }, 2000);
  });
}

// 使用async/await来处理异步操作
async function getData() {
    
    
  try {
    
    
    const data = await fetchData();
    console.log(data); // 输出:这是从服务器获取的数据
  } catch (error) {
    
    
    console.error(error);
  }
}

getData();
  1. Promise:Promise是ES6引入的一种用于管理异步操作的对象。
function fetchData() {
    
    
  return new Promise(function(resolve, reject) {
    
    
    // 模拟异步操作
    setTimeout(function() {
    
    
      const data = '这是从服务器获取的数据';
      resolve(data);
    }, 2000);
  });
}

// 使用Promise的then方法来处理异步操作的结果
fetchData().then(function(data) {
    
    
  console.log(data); // 输出:这是从服务器获取的数据
});

上面提到了promise,下面来说一说promise

JavaScript 中 Promise

promise的基本概念:

Promise是一种用于处理异步操作的对象,它提供了一种更加结构化和可读性更高的方式来管理和组织异步代码。Promise对象代表一个尚未完成、但最终会完成的操作,并在操作完成后返回结果或出错信息。

构造 Promise

new Promise(function (resolve, reject) {
    
    
    // 要做的事情...
});

Promise 的构造函数

Promise 构造函数是 JavaScript 中用于创建 Promise 对象的内置构造函数。
Promise 构造函数接受一个函数作为参数,该函数是同步的并且会被立即执行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject,分别表示 Promise 成功和失败的状态。
起始函数执行成功时,它应该调用 resolve 函数并传递成功的结果。当起始函数执行失败时,它应该调用 reject 函数并传递失败的原因。

一个Promise对象可以有以下三种状态:

  1. Pending(进行中):初始状态,表示异步操作尚未完成。

  2. Fulfilled(已完成):表示异步操作成功完成,并返回一个值作为结果。

  3. Rejected(已拒绝):表示异步操作失败,返回一个错误对象作为拒绝的原因。

Promise对象有以下几个重要的方法:

  1. then():用于处理异步操作的结果。可以通过链式调用多个then()方法,每个then()方法接收上一个操作的结果作为参数,并返回新的Promise对象,以便进行下一步的处理。

  2. catch():用于处理异步操作的错误。当前面的操作抛出异常或Promise被拒绝时,catch()方法将捕获错误并执行相应的处理逻辑。

  3. finally():无论Promise对象是fulfilled还是rejected,finally()方法都会执行。通常用于释放资源或进行清理操作。

function fetchData() {
    
    
  return new Promise(function(resolve, reject) {
    
    
    // 异步操作
    setTimeout(function() {
    
    
      const data = '这是从服务器获取的数据';
      resolve(data); // 异步操作成功,调用resolve()方法
      // reject(new Error('获取数据失败')); // 异步操作失败,调用reject()方法
    }, 2000);
  });
}

// 使用Promise的then()方法处理异步操作的结果
fetchData()
  .then(function(data) {
    
    
    console.log(data); // 输出:这是从服务器获取的数据
  })
  .catch(function(error) {
    
    
    console.error(error); // 输出错误信息
  })
  .finally(function() {
    
    
    console.log('操作完成'); // 无论成功或失败,最终都会执行该函数
  });

在上面的示例中,fetchData函数返回一个Promise对象。通过调用then()方法指定操作成功时的处理逻辑,通过catch()方法指定操作失败时的处理逻辑。finally()方法将在Promise执行完毕后执行,无论成功还是失败。

Promise提供了更好的控制流和错误处理机制,使得异步代码更易于理解、维护和扩展

Promise使用场景

  1. AJAX请求:当发起AJAX请求时,可以使用Promise来处理异步操作并获取服务器的响应数据。通过Promise可以更好地管理请求的成功和失败情况,并进行相应的处理。

  2. 文件加载:在前端开发中,经常需要加载外部文件,如图片、CSS文件、JavaScript文件等。Promise可以用于管理文件加载过程中的异步操作,以确保文件加载成功后再进行后续操作。

  3. 多个异步操作的依赖关系:有时候存在多个异步操作,并且其中一个操作的结果依赖于另一个操作的完成。Promise可以通过链式调用的方式来处理这种依赖关系,使得代码更加清晰和可读。

  4. 并行执行多个异步操作:在某些情况下,我们需要同时执行多个独立的异步操作,并等待它们全部完成后再继续进行后续处理。Promise提供了Promise.all()方法来实现并行执行多个异步操作,并在全部完成后返回结果。

  5. 异步任务的超时控制:有时候需要对异步任务进行超时控制,即如果某个异步任务超过一定时间仍未完成,就中断并进行相应的处理。Promise可以通过结合setTimeout和Promise.race()方法来实现超时控制。

  6. 数据库操作:当进行数据库查询或者与后端交互的时候,常常需要使用Promise来处理异步操作,以便更好地管理数据库操作的结果和异常情况。

总之,无论是在前端还是后端开发中,只要涉及到异步操作,都可以考虑使用Promise来提供更优雅和可靠的代码编写方式。

Promise的优缺点

优点
  1. 更清晰的异步代码:Promise提供了一种结构化的方式来组织和处理异步代码,使得代码更易读、易于理解和维护。通过链式调用的方式,可以将多个异步操作连接起来,形成一个清晰的执行流程。

  2. 更好的错误处理机制:Promise可以通过catch()方法统一处理异步操作的错误,避免了传统回调函数中容易出现的回调地狱(callback hell)问题。错误处理更加集中和可控,提高了代码的健壮性和可靠性。

  3. 支持并行和串行操作:Promise可以通过Promise.all()方法实现多个异步操作的并行执行,并等待它们全部完成后处理结果。同时,也可以通过串联多个then()方法实现异步操作的串行执行,便于管理异步操作之间的依赖关系。

  4. 提供了更加丰富的功能扩展:Promise除了基本的异步操作处理外,还提供了一些常用的方法,如finally()、race()等,可以在异步操作中实现更多的功能需求,例如资源释放、超时控制等。

  5. 与现代JavaScript语法结合紧密:Promise是ES6规范中的一部分,与其他现代JavaScript语法(如箭头函数、async/await)结合紧密。这使得使用Promise更加方便,同时也为异步编程提供了更多选择。

缺点
  1. 学习曲线较陡峭:相比传统的回调函数方式,Promise引入了一些新的概念和使用方法,需要学习者进行一定的学习和适应。初学者可能需要一些时间来理解Promise的工作原理和正确使用方法。

  2. 不支持取消操作:Promise一旦创建,就无法取消或中断正在执行的异步操作。虽然可以通过一些技巧实现类似的效果,但没有官方标准的支持,这可能造成一些困扰。

  3. 不是所有浏览器都支持:尽管Promise是ES6的标准,但在一些旧版本的浏览器中可能不被完全支持。为了兼容性,可能需要使用polyfill或者转换工具(如Babel)进行转换。

综上所述,Promise作为处理异步操作的一种模式和工具,在大多数情况下都具有明显的优势,但也需要注意其适用范围和一些局限性。在实际使用中,可以根据具体需求和项目要求来选择是否使用Promise以及如何使用。

猜你喜欢

转载自blog.csdn.net/He_9a9/article/details/132775630
今日推荐