前端之Promise

06-01 1405阅读

目录

Promise

(1)、回调地狱

(2)、什么是 Promise

(3)、Promise 对象的状态

a、对象的状态不受外界影响

b、状态的变化途径

c、最终结果

(4)、Promise 语法格式

写法一

写法二

(5)、代码示例

(6)、Promise 封装 Ajax

(7)、Promise 的对象方法

Promise.then() 方法

前端之Promise
(图片来源网络,侵删)

Promise.catch() 方法

Promise.all() 方法

前端之Promise
(图片来源网络,侵删)

Promise.race() 方法


(1)、回调地狱

在异步编程的领域中,回调地狱是一个经常困扰开发者的难题。它的产生源于回调函数的过度嵌套,从而导致代码结构变得错综复杂,如同陷入了一个难以挣脱的迷宫。当一个回调函数内部嵌套另一个回调函数时,就像是在一个盒子里不断嵌套更小的盒子,层层深入。随着嵌套层数的逐渐增加,代码的可读性和可维护性就像坐滑梯一样急剧下降,这便是回调地狱的典型特征。

例如,假设我们要模拟发送三个异步请求,并且第二个请求依赖于第一个请求结果中的某个特定值作为参数,第三个请求又依赖于第二个请求结果中的某个值作为参数。如果使用传统的回调函数方式,代码可能会呈现出如下的形态:

    function fn() {
        setTimeout(function () {
            console.log("111");
            setTimeout(function () {
                console.log("222");
                setTimeout(function () {
                    console.log("333");
                }, 1000);
            }, 2000);
        }, 3000);
    }
    fn();

在这段代码中,setTimeout 函数模拟了异步操作,就像是在告诉程序:“先等一会儿,过段时间再执行我里面的内容”。随着嵌套层数一层一层地增加,代码就像是一团乱麻,让人看得眼花缭乱,想要阅读和维护它变得异常困难。想象一下,如果你需要修改其中某个异步操作的逻辑,或者排查一个隐藏在深处的错误,那将会是多么大的挑战。

(2)、什么是 Promise

Promise 是 ES6 引入的一种具有革命性的异步编程解决方案,它就像是一把神奇的钥匙,为我们打开了更高效、更优雅处理异步操作的大门。尽管目前最先进的异步编程方案是 ES8 中的 async 和 await 搭配使用,但实际上,它们就如同站在巨人肩膀上的创新,这个巨人就是 Promise,它们是基于 Promise 实现的。

从语法的角度来看,Promise 是一个构造函数,就像一个神奇的工厂,通过它我们可以创建出 Promise 实例对象。这些实例对象就像是一个个勤劳的小助手,它们专门负责封装异步操作,并且能够准确地获取异步操作的成功或失败结果,让我们对异步操作的掌控更加得心应手。

(3)、Promise 对象的状态
a、对象的状态不受外界影响

Promise 对象就像是一个有着自己独立思想的个体,通过自身独特的状态来精准地控制异步操作。一个 Promise 实例拥有三种截然不同的状态,每一种状态都代表着异步操作的一个特定阶段:

  • pending(进行中):这个状态就像是一场比赛的准备阶段,表示异步操作正在紧张有序地进行当中,结果还在未知的迷雾里,我们还在期待着最终的答案。
  • fulfilled(已成功):当异步操作成功完成,就像是运动员冲过了终点线,我们得到了期望已久的结果,此时就可以信心满满地继续后续的操作,向着下一个目标前进。
  • rejected(已失败):如果异步操作的结果不尽如人意,就像比赛中运动员因为各种原因没能完成比赛,那么就进入了这个状态,它意味着拒绝继续执行后续操作,我们需要去寻找问题、解决问题。
    b、状态的变化途径

    Promise 对象的三种状态就像是被设定了特定轨道的列车,不受外界直接影响,其状态的变化途径只有两条明确的轨道:

    • 从 “pending(未完成)” 到 “fulfilled(成功)”,这是一条充满希望和喜悦的轨道,代表着异步操作顺利达成目标。
    • 从 “pending(未完成)” 到 “rejected(失败)”,这是一条需要我们冷静分析和处理问题的轨道,意味着异步操作遇到了阻碍。

      一旦 Promise 对象的状态发生了变化,就如同列车驶入了既定的站点,会被固定下来,不会再发生新的状态变化。这也正是 Promise 这个名字的深刻内涵,它就像一个庄重的承诺,一旦做出就不能轻易改变。这也就表明 Promise 实例的状态变化在整个生命周期中只可能发生一次,给我们的异步操作带来了确定性和稳定性。

      c、最终结果

      Promise 的最终结果就像是一场冒险的结局,只有两种情况:

      • 异步操作成功时,Promise 实例就像是一个满载而归的探险家,会传回一个值(value),状态也随之变为 fulfilled,这个值就是我们在异步操作中期待得到的宝藏。
      • 异步操作失败时,Promise 实例则像是一个遭遇挫折的勇士,会抛出一个错误(error),状态变为 rejected,这个错误信息就像是给我们的警示信号,帮助我们找到问题所在。
        (4)、Promise 语法格式
        写法一
        new Promise(function (resolve, reject) {
            // resolve 表示成功的回调,用于将 Promise 对象的状态变为 fulfilled,并传递成功的结果,就像是一个传递胜利消息的信使
            // reject 表示失败的回调,用于将 Promise 对象的状态变为 rejected,并传递失败的原因,仿佛是一个告知失败情况的使者
        }).then(function (res) {
            // 当 Promise 对象的状态变为 fulfilled 时,执行此回调函数,就像是在成功的庆典上欢呼庆祝
            console.log('成功:', res);
        }).catch(function (err) {
            // 当 Promise 对象的状态变为 rejected 时,执行此回调函数,仿佛是在失败后进行反思和补救
            console.log('失败:', err);
        });
        写法二
        new Promise(function (resolve, reject) {
            // resolve 表示成功的回调,如同胜利的号角
            // reject 表示失败的回调,好似失败的警钟
        }).then(function (res) {
            // 成功的回调函数,是成功后的喜悦表达
            console.log('成功:', res);
        }, function (err) {
            // 失败的回调函数,是失败后的遗憾诉说
            console.log('失败:', err);
        });

        从上述代码中我们可以清晰地看到,Promise 是一个构造函数,当我们创建实例时,需要传入一个回调函数作为参数,这个回调函数就像是给 Promise 实例下达的初始指令。这个回调函数又包含两个至关重要的参数 resolve 和 reject,它们本身也是函数,各自肩负着重要的使命:

        • resolve 函数的作用是将 Promise 对象的状态从 pending 变为 fulfilled,就像是将未完成的任务标记为成功完成,并且将异步操作的结果作为参数传递出去,让后续的操作能够获取到这个宝贵的成果。
        • reject 函数的作用是将 Promise 对象的状态从 pending 变为 rejected,如同宣告任务失败,并且将异步操作报出的错误作为参数传递出去,方便我们及时发现和解决问题。

          Promise 实例生成以后,就像是一个准备好执行任务的战士,我们可以使用 then 方法分别指定 fulfilled 状态和 rejected 状态的回调函数。then 方法就像是战士的行动指南,它可以接受两个函数作为参数,第一个函数是 Promise 状态为 fulfilled 时的回调函数,是战士胜利后的庆祝仪式;第二个函数是 Promise 状态为 rejected 时的回调函数(通常可以省略第二个函数,使用 catch 方法来捕获失败的异常信息,就像是用一个专门的工具来收集失败的证据)。

          (5)、代码示例
          const promise = new Promise((resolve, reject) => {
              // 模拟异步代码,就像是在模拟一场需要时间的冒险
              setTimeout(() => {
                  // 可以根据实际情况选择调用 resolve 或 reject,就像是在冒险中面临不同的结果选择
                  // resolve(['111', '222', '333']);
                  reject('error');
              }, 2000);
          });
          // 写法一
          promise.then((res) => {
              // 当 Promise 状态变为 fulfilled 时,这个函数被执行,就像是冒险成功后的欢呼
              console.log('success', res);
          }).catch((err) => {
              // 当 Promise 状态变为 rejected 时,这个函数被执行,仿佛是冒险失败后的叹息
              console.log('fail', err);
          });
          // 写法二
          promise.then(
              function (value) {
                  console.log(value);
              },
              function (reason) {
                  console.error(reason);
              }
          );
          (6)、Promise 封装 Ajax
              // 接口地址: https://api.apiopen.top/getJoke
              const p = new Promise((resolve, reject) => {
                  // 1. 创建 XMLHttpRequest 对象,就像是打造一艘探索数据海洋的船只
                  const xhr = new XMLHttpRequest();
                  // 2. 初始化请求,如同为船只设定航行的方向和目标
                  xhr.open("GET", "https://api.apiopen.top/getJoke");
                  // 3. 发送请求,仿佛是让船只扬起风帆,驶向数据的彼岸
                  xhr.send();
                  // 4. 绑定事件,处理响应结果,就像是在船只到达目的地后检查货物
                  xhr.onreadystatechange = function () {
                      // 判断请求是否完成,如同判断船只是否到达目的地
                      if (xhr.readyState === 4) {
                          // 判断响应状态码是否在 200 - 299 之间,表示请求成功,就像是检查货物是否完好无损
                          if (xhr.status >= 200 && xhr.status  
          
          (7)、Promise 的对象方法
          Promise.then() 方法

          then 方法是 Promise 实例中非常重要的一个方法,它就像是一个神奇的连接桥,用于为 Promise 实例添加 fulfilled 状态和 rejected 状态的回调函数。它的返回结果是一个全新的 Promise 对象,这个新对象的状态就像是一个根据不同条件变化的精灵,由回调函数的执行结果来决定,具体情况如下:

          • 返回非 Promise 类型的值:此时新 Promise 对象的状态就像是被赋予了成功的魔法,变为 fulfilled,返回值为该非 Promise 类型的值,就像是得到了一份珍贵的礼物。
          • 返回 Promise 对象:新 Promise 对象的状态就像是在模仿返回的 Promise 对象,取决于返回的 Promise 对象的状态,仿佛是在照镜子。
          • 抛出错误:新 Promise 对象的状态瞬间被阴霾笼罩,变为 rejected,就像是遇到了一场暴风雨。

            then 方法的链式调用更是它的一大亮点,它可以像一条神奇的链条,将多个异步操作有序地连接起来,从而有效解决回调地狱的问题。让我们的代码就像一首优美的乐章,流畅而和谐。

                // 创建 promise 对象,就像是打造一个神奇的盒子,里面装着异步操作的秘密
                const p = new Promise((resolve, reject) => {
                    setTimeout(() => {
                        resolve("用户数据");
                        // reject('出错啦');
                    }, 1000);
                });
                const result = p.then(
                    (value) => {
                        console.log(value);
                        // 1. 返回非 promise 类型的属性,就像是从盒子里拿出一个普通的物品
                        // return 'iloveyou';
                        // 2. 返回 promise 对象,就像是从盒子里拿出另一个神奇的盒子
                        // return new Promise((resolve, reject) => {
                        //     // resolve('ok');
                        //     reject('error');
                        // });
                        // 3. 抛出错误,就像是盒子突然破裂,释放出了错误
                        throw new Error('出错啦!');
                    },
                    (reason) => {
                        console.warn(reason);
                    }
                );
                // 链式调用,就像是将多个神奇的盒子一个接一个地连接起来
                p.then(value => {
                    console.log('第一次 then:', value);
                    return value + ' 处理后';
                }).then(value => {
                    console.log('第二次 then:', value);
                });
            
            Promise.catch() 方法

            catch 方法是 Promise 用来捕获异常的得力助手,专门用于捕获 Promise 状态为 rejected 时的异常信息。它实际上就像是一个语法糖,是 then(null, rejection) 的简洁写法,让我们的代码更加简洁明了。

                const p = new Promise((resolve, reject) => {
                    setTimeout(() => {
                        // 设置 p 对象的状态为失败,并设置失败的值,就像是给盒子贴上失败的标签并写上原因
                        reject("出错啦!");
                    }, 1000);
                });
                // 使用 catch 方法捕获失败信息,就像是用一个网兜接住失败的信号
                p.catch(function (reason) {
                    console.warn(reason);
                });
            
            Promise.all() 方法

            Promise.all() 方法就像是一个团队协作的组织者,用于并发处理多个异步任务。只有当团队中的所有成员(所有任务)都执行完成后,才能得到最终的结果。它接收一个包含多个 Promise 实例的数组作为参数,就像是接收了一组任务清单,然后返回一个新的 Promise 对象。当所有传入的 Promise 实例都变为 fulfilled 状态时,新 Promise 对象的状态就像是团队取得了全面胜利,变为 fulfilled,并将所有 Promise 实例的结果按顺序组成一个数组作为参数传递给回调函数,就像是把所有成员的成果汇总起来展示;如果其中任何一个 Promise 实例变为 rejected 状态,新 Promise 对象的状态就像是团队遭遇了挫折,立即变为 rejected,并将第一个失败的 Promise 实例的错误信息作为参数传递给回调函数,就像是把第一个出现问题的成员的情况告知大家。

            const p1 = new Promise((resolve) => setTimeout(() => resolve('结果1'), 1000));
            const p2 = new Promise((resolve) => setTimeout(() => resolve('结果2'), 2000));
            const p3 = new Promise((resolve) => setTimeout(() => resolve('结果3'), 3000));
            Promise.all([p1, p2, p3]).then((result) => {
                console.log('所有任务完成:', result);
            }).catch((error) => {
                console.error('有任务失败:', error);
            });
            Promise.race() 方法

            Promise.race() 方法就像是一场激烈的赛跑裁判,同样接收一个包含多个 Promise 实例的数组作为参数,返回一个新的 Promise 对象。该方法会返回异步任务数组中第一个执行完的结果,无论这个结果是成功还是失败,就像是宣布第一个冲过终点线的选手获胜,其他任务仍会继续执行,但它们的结果会被忽略,就像是其他选手的成绩不再被关注。

            应用场景:当有几个接口返回相同类型的数据时,可以使用 Promise.race() 方法,哪个接口响应快就使用哪个接口的数据,就像是在众多快递中选择最先送达的那个。

            const p4 = new Promise((resolve) => setTimeout(() => resolve('结果4'), 1000));
            const p5 = new Promise((resolve) => setTimeout(() => resolve('结果5'), 2000));
            Promise.race([p4, p5]).then((result) => {
                console.log('第一个完成的任务结果:', result);
            }).catch((error) => {
                console.error('第一个完成的任务失败:', error);
            });

            通过以上对 Promise 的详细介绍和丰富的示例代码,我们可以真切地感受到 Promise 是一种强大无比的异步编程解决方案。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码