【JavaScript】Promise

概述

JavaScript 中的 Promise 是一种用于处理异步操作的对象,它提供了一种更清晰和可管理的方式来处理异步代码。Promise 用于处理诸如网络请求、文件读取、定时任务等异步操作,以便更好地控制流程和处理错误。以下是 Promise 的基本概念和用法:

  1. Promise 的状态

    • Promise 可以处于三种状态之一:pending(待定)、fulfilled(已成功)、rejected(已拒绝)。
    • 初始状态是 pending,然后可以转换为 fulfilledrejected
  2. 创建一个 Promise

    要创建一个 Promise,你可以使用 new Promise() 构造函数,并传入一个带有两个参数的函数,通常称为执行器函数(executor function)。这个函数接受两个参数:resolvereject,它们是两个回调函数,用于在异步操作完成时分别标志成功和失败。

    const myPromise = new Promise((resolve, reject) => {
      // 异步操作
      if (/* 操作成功 */) {
        resolve(result); // 成功时调用 resolve
      } else {
        reject(error);  // 失败时调用 reject
      }
    });
    
  3. 处理 Promise

    你可以使用 .then() 方法来处理 Promise 的成功状态,以及 .catch() 方法来处理失败状态。这些方法接受回调函数作为参数,这些回调函数在 Promise 完成时被调用。

    myPromise
      .then(result => {
        // 处理成功情况
      })
      .catch(error => {
        // 处理失败情况
      });
    
  4. Promise 链

    你可以使用 .then() 方法构建 Promise 链,每个 .then() 返回一个新的 Promise,可以在其上进行更多的操作。这使得异步操作可以按照顺序执行,使代码更具可读性。

    myPromise
      .then(result => {
        // 第一个异步操作的处理
        return anotherPromise; // 返回一个新的 Promise
      })
      .then(result => {
        // 第二个异步操作的处理
      })
      .catch(error => {
        // 处理任何错误
      });
    
  5. Promise.all()

    Promise.all() 是一个实用工具,它接受一个 Promise 数组,并在所有 Promise 都成功完成时触发一个回调。如果其中任何一个 Promise 失败,则整个 Promise.all() 将失败。

    const promises = [promise1, promise2, promise3];
    
    Promise.all(promises)
      .then(results => {
        // 所有 Promise 都成功时执行
      })
      .catch(error => {
        // 如果任何一个 Promise 失败,将触发此处
      });
    
  6. Promise.race()

    Promise.race()Promise.all() 类似,但它在第一个 Promise 解决(无论是成功还是失败)时触发回调,而不是等待所有 Promise 完成。

    const promises = [promise1, promise2, promise3];
    
    Promise.race(promises)
      .then(result => {
        // 第一个完成的 Promise 触发
      })
      .catch(error => {
        // 如果第一个失败的 Promise 触发
      });
    

优势

  1. 可以避免回调地狱:将回调函数转换成了链式调⽤,代码可读性更好。
  2. 可以⽀持多个并发请求:Promise.all() 可以让多个 Promise 并⾏执⾏,提⾼了执⾏效率。
  3. 可以在异步代码中捕获错误:Promise.catch() 可以捕获异步代码中的错误。

使用场景

  1. Ajax 请求:Promise 可以⽤于异步获取数据,当数据请求成功时,调⽤ Promise 的 resolve ⽅法,否则调⽤ reject ⽅法。
  2. 定时器:Promise 可以结合定时器⼀起使⽤,实现定时器的延时操作。
  3. 图⽚加载:Promise 可以⽤于图⽚的异步加载,当图⽚加载成功时,调⽤ Promise 的 resolve ⽅法,否则调⽤ reject ⽅法。
  4. 优化回调函数:将回调函数转换成 Promise 链,提⾼代码可读性。
  5. 实现并发请求:Promise.all() 可以让多个请求并⾏执⾏。
  6. 解决回调地狱:将嵌套的回调函数转换成链式调⽤,提⾼代码可读性。

使用总结

ES6 中的 Promise 是⼀种⽤于处理异步操作的机制,它可以更加优雅地处理异步操作,避免了回调地狱的问题。在 JavaScript 中,Promise 对象代表⼀个异步操作的最终状态(成功或失败),并且可以链式调⽤。

Promise 对象提供了 then ⽅法,可以将异步操作成功的回调函数和失败的回调函数注册到 Promise 对象上,当 Promise 对象状态变为 Fulfilled 或 Rejected 时,会⾃动调⽤对应的回调函数。then ⽅法中的回调函数并不是⽴即执⾏,⽽是放⼊微任务队列中,在 JavaScript 主线程执⾏栈为空时,才会被调⽤执⾏。

Promise构造函数接受⼀个函数作为参数,该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不⽤⾃⼰部署。

resolve函数的作⽤是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为
resolved),在异步操作成功时调⽤,并将异步操作的结果,作为参数传递出去;reject函数
的作⽤是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在
异步操作失败时调⽤,并将异步操作报出的错误,作为参数传递出去。

Promise实例⽣成以后,可以⽤then⽅法分别指定resolved状态和rejected状态的回调函数,即then 的两个参数,第⼀个回调函数是Promise对象的状态变为 resolved时调⽤,第⼆个回调函数是Promise对象的状态变为rejected时调⽤,且第二个回函数参数是可选的。 then⽅法返回的是⼀个新的Promise实例。

此外,Promise 还提供了其他的方法:

  1. catch ⽅法:捕获 Promise 对象的错误信息,相当于 then(null, onRejected)。
  2. finally ⽅法:⽆论 Promise 对象状态如何,finally ⽅法总是会执⾏,通常⽤于资源清理等操作。
  3. Promise.all ⽅法:接收⼀个 Promise 对象数组,当所有 Promise 对象状态都变为
    Fulfilled 时,返回⼀个 Promise 对象,状态为 Fulfilled,并携带所有 Promise 对象的结
    果;当有任意⼀个 Promise 对象状态变为 Rejected 时,返回的 Promise 对象状态变为 Rejected,并携带第⼀个 Promise 对象的错误信息。
  4. Promise.race ⽅法:接收⼀个 Promise 对象数组,当其中任意⼀个 Promise 对象状态变为 Fulfilled 或 Rejected 时,返回⼀个 Promise 对象,状态为对应 Promise 对象的状态,并携带对应 Promise 对象的结果或错误信息。

练习题

如何顺序执行 10 个异步任务?

function asyncTask1() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("Async task 1");
      resolve();
    }, 1000);
  });
}
function asyncTask2() {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("Async task 2");
      resolve();
    }, 2000);
  });
}
// 顺序执⾏异步任务
asyncTask1()
  .then(() => {
    return asyncTask2();
  })
  .then(() => {
    // 执⾏完异步任务1和异步任务2后的逻辑
  });

或者换一种写法:

function fn1() {
  return new Promise((resolve, reject) => {
    console.log('fn1执⾏')
    setTimeout(() => {
      console.log('fn1结束')
      resolve('fn1传递过去的参数')
    }, 1000)
  })
}
function fn2(data) {
  return new Promise((resolve, reject) => {
    console.log('fn2执⾏,接收的参数', data)
    setTimeout(() => {
      resolve('fn2传递过去的参数')
    }, 1000)
  })
}
function fn3(data) {
  return new Promise((resolve, reject) => {
    console.log('fn3执⾏,接收的参数', data)
    setTimeout(() => {
      resolve('fn3传递过去的参数')
    }, 1000)
  })
}
fn1().then(fn2).then(fn3).then(res => {
  console.log('最后⼀个', res)
})

在这里插入图片描述

或者使用 async 和 await :

async function runAsyncTasks() {
  await asyncTask1();
  await asyncTask2();
  // 执⾏完异步任务1和异步任务2后的逻辑
}
runAsyncTasks();

当然还可以使用生成器:

function* main() {
  const res1 = yield fn1("开始");
  const res2 = yield fn2(res1);
  const res3 = yield fn3(res2);
  console.log(res3, "全部执⾏完毕");
}
const task = main();
task.next();
function fn1(data) {
  setTimeout(() => {
    console.log("fn1执⾏", data);
    task.next("fn1执⾏完毕");
  }, 1000);
}
function fn2(data) {
  setTimeout(() => {
    console.log("fn2执⾏", data);
    task.next("fn2执⾏完毕");
  }, 1000);
}
function fn3(data) {
  setTimeout(() => {
    console.log("fn3执⾏", data);
    task.next("fn3执⾏完毕");
  }, 1000);
}
console.log("我是最开始同步执⾏的");

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值