js学习Promise

目录

1. 基本概念

2. 基本语法

3. Promise链式调用

4. Promise.all和Promise.race

5. Promise的错误处理

6. Promise在实际开发的使用

7. async/await语法糖


1. 基本概念

Promise是一种异步编程的解决方案,用于处理异步操作的结果。可以将Promise理解为是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

1. Promise状态

Promise有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。

- pending:Promise对象的初始状态,表示异步操作还没有完成。
- fulfilled:异步操作成功完成,Promise对象的状态从pending变为fulfilled。
- rejected:异步操作未成功完成,Promise对象的状态从pending变为rejected。

例如,当执行一个耗时的异步操作时,Promise可以返回一个pending状态的Promise对象,表示操作尚未完成。当异步操作完成时,如果成功,则Promise对象变为fulfilled状态,包含异步操作返回的结果;如果失败,则Promise对象变为rejected状态,包含异步操作失败的原因。

2. Promise基本方法

- Promise构造函数:通过`Promise`构造函数来创建一个Promise对象,接受一个函数为参数,该函数带有两个参数:`resolve`和`reject`。
- `resolve`方法:调用`resolve`就表示Promise对象的状态变为fulfilled。
- `reject`方法:调用`reject`就表示Promise对象的状态变为rejected。
- `then`方法:通过`then`方法获取异步操作的结果,可以链式调用,也可以用于捕捉异常信息。
- `catch`方法:用于捕捉异常信息,返回一个新的Promise对象,以便继续传递错误信息。

3. Promise执行顺序

Promise对象的状态只能从pending变为fulfilled或rejected,一旦状态变化,就不会再变了。Promise对象的状态改变后,会触发`then`方法绑定的回调函数或`catch`方法捕捉的错误信息。另外,Promise的回调函数是异步执行的,不会阻塞主线程。

4. 回调地狱

回调地狱(Callback Hell)是指在嵌套多层回调函数时,代码变得难以阅读和理解的情况。在JavaScript中,由于是单线程执行的,处理异步任务时通常需要使用回调函数来进行处理。但是,当异步任务比较复杂、嵌套层级比较深的情况下,就会导致回调函数嵌套回调函数,形成回调地狱。

例如:

getUserInfo(function(user) {
  getUserOrders(user.id, function(orders) {
    getOrderDetails(orders[0].id, function(details) {
      updateUserProfile(user.id, details, function(result) {
        console.log(result)
      })
    })
  })
})

在上述代码中,当需要访问嵌套层级更深的异步任务时,每增加一层嵌套就会导致代码的可读性、可维护性和可扩展性下降,会导致代码难以维护。此时就需要使用Promise、async/await等异步编程的解决方案来避免回调地狱的问题,使得代码更容易理解和维护。

2. 基本语法

1. 创建Promise对象

可以使用`new Promise()`来创建一个Promise对象,语法如下:

const promise = new Promise(function(resolve, reject) {  
  // 异步任务  
  if (异步任务成功) {  
    resolve(成功的结果);  
  } else {  
    reject(失败的原因);  
  }  
});

以上代码中,`Promise()`构造函数接受一个函数参数,该函数包含两个参数:`resolve`和`reject`。`resolve`用于表示异步操作成功的结果,`reject`用于表示异步操作失败的原因。因为异步操作的结果是不确定的,所以需要将`resolve`和`reject`作为参数传递进来,通知Promise对象状态变化。

2. Promise的then()方法

`Promise`对象的`then()`方法用于指定异步操作成功的回调函数,接收一个成功的回调函数作为参数。

promise.then(function(result) {  
  // 成功后的结果处理
}, function(reason) {
  // 发生错误的处理
});

在上面的代码中,`then()`方法中的函数会在异步操作成功时被调用,处理结果并返回。

3. Promise的catch()方法

`Promise`对象的`catch()`方法用于指定异步操作失败的回调函数,接收一个失败的回调函数作为参数。

promise.catch(function(reason) {
  // 失败时的处理
});

在上面的代码中,`catch()`方法中的函数会在异步操作失败时被调用,处理错误信息并返回。

4. Promise的finally()方法

`Promise`对象的`finally()`方法用于指定异步操作不论成功或失败都需要执行的回调函数。该方法不接收任何参数。

promise.finally(function() {
  // 不论成功或失败都会执行
});

3. Promise链式调用

Promise的链式调用是指通过`then()`方法返回另一个Promise对象,从而实现对异步操作的链式调用。

Promise的链式调用有以下几个特点:

1. `then()`方法总是返回一个Promise对象。
2. 如果在`then()`方法中返回结果是一个值或者是一个Promise对象,那么后续的`then()`方法会正常执行。
3. 如果在`then()`方法中抛出异常或者返回一个被拒绝的Promise对象,那么后续的`then()`方法会被跳过,直接执行`catch()`或者最后的`finally()`方法。

下面是一个简单的Promise链式调用的例子:

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  }, 2000);
});

promise.then((x) => {
  console.log(x);
  return x + 1;
})
.then((y) => {
  console.log(y);
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(y * 2);
    }, 2000);
  });
})
.then((z) => {
  console.log(z);
})
.catch((err) => {
  console.error(err);
});

在上面的代码中,我们创建了一个Promise对象,使其在2秒后返回1。接着我们对该Promise对象进行链式调用,第一个回调函数中输出1并返回2,第二个回调函数中输出2并返回一个新的Promise对象,该Promise对象在2秒后返回y * 2的值。最后一个回调函数中输出y * 2的值。

在实际应用中,常常会使用Promise的链式调用来进行复杂的异步操作。通常可以将一个函数功能拆分成多个步骤,并使用then()方法将其串联起来形成链式调用,以实现异步任务的处理和结果的传递。

4. Promise.all和Promise.race

`Promise.all()`和`Promise.race()`是Promise对象的两个常用方法。

1. `Promise.all()`

`Promise.all()`方法接收一个Promise对象数组作为参数,返回一个Promise对象,并且会等待所有的Promise对象都结束。当所有Promise对象都成为fulfilled状态时,`Promise.all()`方法的状态变为fulfilled,返回值是所有Promise对象返回值组成的数组。否则,状态为rejected,返回值是一个Promise对象的拒绝原因。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise1');
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise2');
  }, 2000);
});

Promise.all([promise1, promise2]).then((result) => {
  console.log(result); // ['promise1', 'promise2']
}).catch((error) => {
  console.log(error);
});

在上面的代码中,我们通过`Promise.all()`方法来等待promise1和promise2的完成。由于promise1和promise2分别需要1秒和2秒才能完成,所以`Promise.all()`方法会等待2秒,最终输出结果为['promise1', 'promise2']。

2. `Promise.race()`

`Promise.race()`方法接收一个Promise对象数组作为参数,返回一个Promise对象。只要有一个Promise对象的状态发生变化,整个Promise对象的状态就跟随这个Promise对象的状态变化。返回值是第一个变化状态的Promise对象的返回值。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise1');
  }, 1000);
});

const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('promise2');
  }, 2000);
});

Promise.race([promise1, promise2]).then((result) => {
  console.log(result); // 'promise1'
}).catch((error) => {
  console.log(error);
});

在上面的代码中,我们通过`Promise.race()`方法来等待promise1和promise2的完成。由于promise1需要1秒才能完成,而promise2需要2秒才能完成,所以`Promise.race()`方法会等待1秒,最终输出结果为'promise1'。

5. Promise的错误处理

在异步编程中,通常需要处理异步任务的错误。Promise提供了两种错误处理方式:使用`catch()`方法捕捉错误,或者在`then()`方法的第二个参数中处理错误。

1. 使用`catch()`方法捕捉错误

Promise对象的`catch()`方法用于处理Promise对象发生的错误,它接收一个回调函数作为参数。如果Promise对象变为rejected状态,则调用该回调函数处理错误。如果`catch()`方法中没有处理错误,则错误将会向下传递直到被捕获为止。

const promise = new Promise((resolve, reject) => {
  const randomNumber = Math.random();
  if (randomNumber < 0.5) {
    resolve('成功');
  } else {
    reject('失败');
  }
});

promise.then((result) => {
  console.log(result);
}).catch((error) => {
  console.log(error);
});

在上面的代码中,我们创建了一个Promise对象,如果生成的随机数小于0.5,则Promise对象状态变为fulfilled,否则状态变为rejected。在`then()`方法中处理成功和在`catch()`方法中处理失败。

2. 使用`then()`方法的第二个参数处理错误

Promise对象的`then()`方法可以接收两个参数,第一个参数是处理结果的回调函数,第二个参数是处理异常的回调函数。当异步任务成功时会调用第一个参数,当异步任务失败时会调用第二个参数。

const promise = new Promise((resolve, reject) => {
  const randomNumber = Math.random();
  if (randomNumber < 0.5) {
    resolve('成功');
  } else {
    reject('失败');
  }
});

promise.then((result) => {
  console.log(result);
}, (error) => {
  console.log(error);
});

以上是使用`catch()`方法和`then()`方法的第二个参数处理Promise对象的错误。需要注意,如果同时使用了`catch()`方法和`then()`方法的第二个参数,`then()`方法中的回调函数会优先执行,因此,一般来说推荐使用`catch()`方法来捕捉错误。

6. Promise在实际开发的使用

在实际开发中,Promise常被用于处理异步任务,例如发送http请求、获取数据等。下面举一个例子来说明Promise在项目中如何使用。

假设有一个需求:从服务器获取一个用户信息,然后根据用户信息获取该用户的订单列表,最后计算该用户订单总数并输出。可以使用Promise来实现。

首先,编写获取用户信息的函数`getUserInfo(userId)`:

function getUserInfo(userId) {
  return new Promise((resolve, reject) => {
    // Ajax请求获取用户信息
    $.ajax({
      url: '/user/info',
      data: { userId },
      success: (res) => {
        resolve(res);
      },
      error: (err) => {
        reject(err);
      }
    });
  });
}

在上面的代码中,我们使用jQuery的Ajax方法来发送http请求获取用户信息,并使用Promise来处理异步任务。

接着,编写获取订单列表的函数`getUserOrders(userId)`:

function getUserOrders(userId) {
  return new Promise((resolve, reject) => {
    // Ajax请求获取订单列表
    $.ajax({
      url: '/order/list',
      data: { userId },
      success: (res) => {
        resolve(res);
      },
      error: (err) => {
        reject(err);
      }
    });
  });
}

在上面的代码中,我们使用jQuery的Ajax方法来发送http请求获取用户订单列表,并使用Promise来处理异步任务。

最后,编写计算订单总数的函数`calculateTotalOrders(orders)`:

function calculateTotalOrders(orders) {
  // 计算订单总数
  let total = 0;
  for (let i = 0; i < orders.length; i++) {
    total += orders[i].count;
  }
  return total;
}

在上面的代码中,我们根据订单列表计算订单总数。

根据上述函数,我们可以编写实际应用场景的代码:

getUserInfo(userId)
  .then((userInfo) => {
    return getUserOrders(userInfo.userId);
  })
  .then((orders) => {
    const totalOrders = calculateTotalOrders(orders);
    console.log(`用户订单总数为:${totalOrders}`);
  })
  .catch((err) => {
    console.error(err);
  });

在上面的代码中,我们调用`getUserInfo(userId)`函数获取用户信息,然后调用`getUserOrders(userInfo.userId)`函数获取用户订单列表,接着调用`calculateTotalOrders(orders)`函数计算订单总数,并输出结果。如果发生错误,则在`catch()`方法中对错误进行处理。

7. async/await语法糖

async和await是ES7中的语法糖,可以更简单易读地处理异步操作。
async函数会返回一个Promise对象。
await只能在async函数中使用,可以等待Promise完成并返回结果,或抛出错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值