大家好,我是 HoMeTown ,Promise想必大家都知道,在平时的开发工程中也经常会有用到,但是Promise作为ES6的重要特性,其实还拥有很多丰富的知识,本文面向比较初级一些的同学,可以帮你搞懂Promise到底做了什么,顺便起到一个备忘录的作用。

Promise?

Promsie中文直译 承诺 ,其实也很好理解,就是无论这个异步任务最后的结果怎么样,我承诺会给你一个结果。

Promise在JavaScript中是一个处理异步代码的解决方案,他的出现解决了JavaScript异步编程回调地狱的问题(此处 que一下wxapi)。

Promise对象代表一个异步操作,有三种状态: pending(进行中) fulfilled(已成功) rejected(已失败)

一个Promsie实例必然处于上述的三个状态直译。

Promise的运行机制

当Promise被实例化后,其实例会处于 pending 状态,一般情况下,遇到以下操作,Promise的状态会被改变:

  • 执行 resolve
  • 执行 reject
  • 下面举个例子:

    const p1 = new Promise((resolve, reject) => {
        resolve('成功')
        console.log('这里还能执行吗? -- p1')
        reject('失败')
        console.log('这里呢? -- p1')
      console.log(p1,'p1')
      const p2 = new Promise((resolve, reject) => {
        reject('失败')
        resolve('成功')
        console.log('这里还能执行吗? -- p2')
      console.log(p2, 'p2')
      const p3 = new Promise((resolve, reject) => {})
      console.log(p3, 'p3')
      const p4 = new Promise((resovle, reject) => {
        throw 'error'
      console.log(p4, 'p4')
      const p5 = new Promise((resovle, reject) => {
        throw 'error'
        resolve('成功')
        reject('失败')
      console.log(p5, 'p5')
      const p6 = new Promise('测试')
      console.log(p6, 'p6')
    

    执行结果如下:

    通过上图中的执行结果我们可以发现:

  • new Promise 返回了一个Promise实例
  • 传入Promise构造函数中的执行函数,会被立即执行,且拥有了两个参数resolve reject
  • resolve操作 之后 PromiseState(状态) 会变成 flufilled, PromiseResult 为 resolve的参数
  • reject操作 之后 PromiseState(状态) 会变成 rejected,PromiseResult 为 rejected的参数
  • 报错之后 之后 PromiseState(状态) 会变成 rejected,PromiseResult 为 报错信息
  • 如果没有执行resolve/reject,也没有出现报错,PromiseState(状态) 会保持 pending,PromiseResult 为 undefined
  • 一旦执行resolve/reject,或者出现报错Promise会修改Promise实例的PromiseState & PromiseResult,后续的代码还会继续执行
  • Promise的使用

    Promise作为一个构造函数可以被new关键字进行实例化,并在.then.catch分别取到成功和失败的结果。

    p1.then(res => { console.log(res, '成功')}).catch(err => {console.log('失败', err)})
    

    Promise封装请求器

    function request({ method = "GET", url = "", data = {}, timeout = 10000 }) {
      const xhr = new XMLHttpRequest();
      return new Promise((resolve, reject) => {
        xhr.onreadystatechange = function () {
          if (xhr.readyState !== 4) return reject("xhr readyState error");
          if (xhr.timeout > timeout) return reject("request timout");
          if (xhr.status === 200) {
            resolve(JSON.parse(xhr.responseText));
          } else {
            reject(xhr.statusText);
        xhr.open(method, url);
        xhr.send(data);
    

    测试请求器:

    // 测试请求器
    request({
      method: "GET",
      url: "https://api.apiopen.top/api/getHaoKanVideo?page=0&size=2",
    }).then((res) => {
      console.log(res, "获取数据成功");
    

    结果如下:

    Promise原型上的方法

    Promise.prototype.then

    Promise.prototype具有then方法,也就是说,每一个Promsie实例对象都可以调用then方法得到Promsie成功的结果。

    then方法的第一个参数是flufilled状态的回调函数,第二个参数是rejected状态的回调函数,举个栗子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('good')
        reject('bad'); // 这里不会被执行
      }, 1000);
    p1.then(
      (res) => {
        console.log(res, "成功");
      (err) => {
        console.log(err, "失败");
    

    执行结果如下:

    Promise.prototype.catch

    catch() 方法返回一个Promise,用捕捉指定错误并且处理错误。它的行为与调用Promise.prototype.then(_, onRejected) 相同,举个栗子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject("bad");
      }, 1000);
    p1.catch(err => {
        console.log(err)
    

    执行结果如下:

    then链

    有趣的是,then方法也返回了一个Promsie实例,那就意味着,可以继续执行.then进行下一次的结果获取,像这样:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("good");
        reject("bad");
      }, 1000);
    p1.then((res) => {
      console.log(res, "then1");
    }).then(res => {
        console.log(res, 'then2') // undefined 'then2'
    

    then方法中,你可以通过return决定下一次的结果是什么:

    返回基本数据类型或者引用数据类型,下一次接受该数据,状态为flufilled,可继续.then

    返回一个Promsie

  • 状态为flufilled,可继续执行.then
  • 状态为pending,不会继续执行.then,直到当前Promise实例得到一个有效的状态
  • 状态为rejected,不会继续执行.then,直接走到.catch
  • 什么都没返回,执行.then,结果为undefined

    出现报错,直接走到.catch

    Promise.prototype.finally

    finally方法用于不管结果如何,都会执行的操作,可以避免相同的逻辑在then&catch重复写的情况,举个栗子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject("bad");
      }, 1000);
    p1.then((res) => {
      console.log(res, "成功");
      .catch((err) => {
        console.log(err, "失败");
      .finally(() => {
        console.log("不管成功不成功");
    

    执行结果如下:

    Promise构造函数上的方法

    Promise的prototype上也有一些函数可以使用,比如(race、all、any、race等):

    Promise.resolve

    Promise.resolve方法不是excutefunc上的resovle方法,而是原型上的方法,该方法接受一个参数,返回一个状态为fulfilled 的 Promise实例,如果参数为基本类型或者引用类型,则PromiseResult为传递进来的参数,举个栗子

    const pstring = Promise.resolve('HoMeTowm')
    console.log(pstring,'字符串 Promise实例')
    const pnumber = Promise.resolve(123)
    console.log(pnumber,'数字 Promise实例')
    const pboolean = Promise.resolve(true)
    console.log(pboolean,'布尔值 Promise实例')
    const pobject = Promise.resolve({name: 'HoMeTowm'})
    console.log(pobject,'对象 Promise实例')
    console.log('......')
    

    执行结果如下:

    如果传递进来的是一个Promise实例,则完整的返回这个Promise实例,举个栗子:

    const p1 = new Promise((resolve) => {
        resolve('Promise 实例: p1')
    const ppromise = Promise.resolve(p1)
    console.log(ppromise, 'Promise.resolve的实例:ppromise')
    

    执行结果如下:

    如果没有传参数,返回PromiseResultundefined的Promise实例:

    const pundefined = Promise.resolve()
    console.log(pundefined)
    

    执行结果如下:

    Promise.reject

    Promise.reject方法相同,也会返回一个Promise实例,不同的是PromiseStatusrejectd,用上面的栗子进行测试:

    const pstring = Promise.reject('HoMeTowm')
    console.log(pstring,'字符串 Promise实例')
    const pnumber = Promise.reject(123)
    console.log(pnumber,'数字 Promise实例')
    const pboolean = Promise.reject(true)
    console.log(pboolean,'布尔值 Promise实例')
    const pobject = Promise.reject({name: 'HoMeTowm'})
    console.log(pobject,'对象 Promise实例')
    console.log('......')
    

    执行结果如下:

    Promise.all

    Promise.all方法,可以发起并发请求,然后再所有Promise都脱离pending状态后,统一返回结果,接受一个数组作为参数,数组中的项为Promise实例(如果不是的话,传啥返回啥),返回一个Promise实例,PromiseResult每个实例对应的结果PromiseState所有的实例未脱离pending之前为pending,举个例子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("p1 resolve执行");
        resolve("p1 的结果");
      }, 1000);
    const p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("p2 resolve执行");
        resolve("p2 的结果");
      }, 2000);
    const pnumber = 510
    const pall = Promise.all([p1, p2, pnumber]);
    console.log("promise.all 的结果未完成:", pall);
    pall.then((res) => {
      console.log(res, "全部的结果");
      console.log("promise.all 的结果已完成:", pall);
    

    执行结果如下:

    数组中如果有一个失败,则返回失败的结果,只要失败了就返回!举个栗子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('p1 还能执行')
        throw "哎呀,p1报错了";
      }, 1000);
    const p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log('p2 还能执行')
        resolve("p2 的结果");
      }, 2000);
    const preject = Promise.reject("Promsie.reject 失败");
    const pall = Promise.all([p2, p1, preject]);
    console.log("promise.all 的结果未完成:", pall);
      .then((res) => {
        console.log(res, "全部的结果");
        console.log("promise.all 的结果已完成:", pall);
      .catch((err) => {
        console.log(err, "失败了 嘤嘤嘤");
    

    执行结果如下:

    Promise.allSettled

    Promise.allSettled用法与Promise.all相同,不同的是,Promise.allSettled不会因为有一个失败,就走到catch,而是会走到then,并告诉你,哪个失败了,那个成功了,举个栗子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
         reject('p1 失败')
      }, 1000);
    const p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("p2 成功");
      }, 2000);
    const pall = Promise.allSettled([p2, p1, Promise.reject(1)]);
    console.log("promise.allSettled 的结果未完成:", pall);
      .then((res) => {
        console.log(res, "全部的结果");
        console.log("promise.allSettled 的结果已完成:", pall);
      .catch((err) => {
        console.log(err, "失败了 嘤嘤嘤");
    

    执行结果如下:

    Promise.race

    Promise.race与其字面意思相同,竞速,即哪个先完成,就以哪个为结果,参数与Promise.all相同,举个栗子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
         reject('p1 失败')
      }, 1000);
    const p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("p2 成功");
      }, 2000);
    const prace = Promise.race([p2, p1]);
    prace.then(res => {
        console.log(res,'成功')
    }).catch(err => {
        console.log(err, '失败')
    

    执行结果如下:

    Promise.any

    Promise.any方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例,有一个子实例成功就算成功,全部子实例失败才算失败,返回AggregateError: All promises were rejected,举个栗子:

    const p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
         reject('p1 失败')
      }, 1000);
    const p2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve("p2 成功");
      }, 2000);
    const prace = Promise.any([p2, p1]);
    prace.then(res => {
        console.log(res,'成功')
    }).catch(err => {
        console.log(err, '失败')
    

    执行结果如下:

    p2改为reject之后,执行结果如下:

    下次见~ 我的朋友,我是HoMeTown👨‍💻‍,➕我VX,💊你进群,这是一个大家共同成长、共同学习的社群!在这里你可以:讨论技术问题、参与日积月累计划、了解前端资讯、打听应聘公司、获得内推机会、聊点有的没的。

    👉 vx: hometown-468【单独拉你】

    👨‍👩‍👧 公众号:秃头开发头秃了 【关注回复“进群”】

    🤖 Blog:HoMeTown'Blog【点开看看】

    羊了个羊 🐑 一夜爆火,我却开始偷偷抹眼泪...

    分享 11 张巨好看的PC端界面!!!

    敢在我工位装摄像头?吃我一套JS ➕ CSS组合拳!!👊🏻

    前端老司机 70+ 实用工具网站分享(建议收藏!)🔥🔥

    【Git】 什么!?都快2023年了还搞不清楚 git rebase 与 git merge!?😮

    我用前端【最新】技术栈完成了一个生产标准的项目【Vue3 + TS + Vite + Pinia + Windicss + NavieUI】

    🤷‍♂️ 怒砸 30w+ 矿石抽礼盒后,我通透了...【掘金 · 幸运大转盘Vue3版】

    巧用NodeJs帮老板解决个人需求!老板娘直呼:"牛!niu!🐂!"

    使用eslint + prettier + husky + lint-staged 约束项目的最佳实践!

    【小程序】爆肝 3 天总结的微信小程序优化指南(收藏夹吃灰吧!)🔥🔥

    【VUE】从源码角度说清楚MVVM!实现v-model!真的很简单!🔥

    【CSS】5分钟带你彻底搞懂 W3C & IE 盒模型!🔥🔥

    【CSS】有意思的BFC:Block Formatting Context(块格式化上下文)!🤡

    【CSS】聊一聊CSS像素、设备像素、设备独立像素、dpr、ppi 之间的区别

    【性能】7分钟带你了解【尤大】都在使用的 Chrome Runtime Performance Debug!

    【源码角度】7分钟带你搞懂ESLint核心原理!

    【JavaScript】手把手教你写高质量 JavaScript 异步代码!

    ............... 查看更多 ...............

    HoMeTown 公众号 @ 秃头开发头秃了  4,985 文章被阅读  537,218 Promise? Promise的运行机制 Promise的使用 Promise封装请求器 Promise原型上的方法 Promise.prototype.then Promise.prototype.catch then链 Promise.prototype.finally Promise构造函数上的方法 Promise.resolve Promise.reject Promise.all Promise.allSettled Promise.race Promise.any