Promise 深度学习

news2024/11/19 13:18:03

文章目录

    • Promise 由来
    • Promise的用法
    • reject的用法
      • finally
    • all的用法
    • race的用法
    • 总结

Promise 由来

我们处理异步函数最普通的方法是这样的,等待上一次请求结束再执行下一步操作:

// 一般以定时器来模拟一次请求
setTimeout(() => {
  console.log("first");
  // 处理的内容 或者 下一次请求
  // TODO
}, 1000);

这是两次的请求,看着是比较简单,这么写好像也没什么影响,但如果TODO后面还有多个请求时:

// 用多个定时器来模拟多个请求
setTimeout(() => {
  console.log("第一次处理");
  setTimeout(() => {
    console.log("第二次处理");
    setTimeout(() => {
      console.log("第三次处理");
        setTimeout(() => {
          console.log("第四次处理");
          // TODO
        }, 4000)
    }, 3000)
  }, 2000)
}, 1000);

回调函数中嵌套回调函数,就是回调地狱,这种写法仔细看我们肯定是能看得出来的,但是无限嵌套之后,代码的可读性非常差,日常维护也是很繁琐的事情。为了更好的处理嵌套格式的代码,我们就可以使用Promise。这当然也是ES6(ES2015)中最重要的特性之一,开发中经常使用,面试的时候也经常问。

Promise的用法

我们可以先打印看看,Promise长什么样:

console.dir(Promise);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMw6cXvW-1687913685665)(C:\Users\zy3\Desktop\study\drop-of-water\water\web\Vue2.0\2023\img\打印出的Promise.png)]

显而易见的Promise是一个构造函数,本身带着 all、race、reject、resolve等方法,prototype原型上也带着 catch、then等方法。new Promise:

// 一般Promise new的时候都喜欢用一个函数包一下,这里还是使用定时器代替请求
const p = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    console.log("时间到了");
   	resolve("成功操作")
  }, 1000)
});
p.then(res => {
  console.log(res);
});

// 执行后的结果为: 
// 时间到了
// 成功操作

Promise的构造函数接收了一个参数,是一个函数,并且函数中传入两个参数 resolve、reject,分别是异步操作执行成功后的回调函数和异步操作执行失败后的回调函数(这么描述并不是正确的,实际上是 resolve将Promise的状态置为fullfiled,reject是将Promise的状态置为rejected,状态操作是不可逆的,Promise一开始的状态是pending初始态,状态改变方式也就两种)。

上面代码,定时器一秒之后输出“时间到了”,并且调用resolve方法。在异步任务执行完之后,再打印“成功操作”,这就是Promise的作用:将原来的回调写法分离出来,在异步操作执行完之后,用链式调用的写法执行回调函数

这里只是最简单的Promise,如果要改造前面写的多个定时器请求,我们可以这样写:

// Promise优势在于,可以在then方法中继续写Promise对象并返回,然后继续调用then来进行回调操作
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("第一次请求");
    resolve();
  }, 1000)
})

// 链式操作的用法
p1
  .then(() => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("第二次请求");
        resolve()
      }, 2000)
    })
  })
  .then(() => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("第三次请求");
        resolve();
      }, 3000)
    })
  })
  .then(() => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        console.log("第四次请求");
      })
    }, 4000)
  })

// 换一种写法,执行结果一样 将函数定义一下
function p1() {
  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("第一次请求");
      resolve(1);
    }, 1000)
  })
  return p;
}

function p2() {
  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("第二次请求");
      resolve(2);
    }, 1000)
  })
  return p;
}

function p3() {
  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("第三次请求");
      resolve(3);
    })
  })
  return p;
}

// p1只是返回函数,没有调用,需要在p1后面添加一个 ()
p1()
  .then(res => {
    console.log(res);
    return p2();
  })
  .then(res => {
    console.log(res);
    return p3();
  })
  .then(res => {
    console.log(res);
  })
// 这样就没有回调地狱了

reject的用法

上面的代码都只用了resolve,我们还没用过reject。事实上前面的代码假设都是成功的,还没有失败的情况:

// 一个在定时器中的随机生成[0,10)随机数的函数
function getNumFn() {
 const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      let num = Math.ceil(Math.random() * 10); // 随机生成1-10(不包含)的随机数
      if (num <= 5) {
        // 模拟成功时的操作
        resolve("数字小于5", num);
      } else {
        // 模拟失败时的操作
        reject("数字大于5", num);
      }
    }, 1000)
 });
 return p;
};

getNumFn()
  .then(res => {
    console.log("resolve", res);
  })
  .catch(err => {
    console.log("reject", err);
  })

我们可以看出数字小于5的时候会执行then里的内容,数字大于5时会执行catch中的操作,一般resolve对应then,reject对应catch;但其中then是一个卷王,它可以接收两个参数,一个对应resolve的回调,第二个对应的reject的回调(曾经有个面试官问过我then能接收几个参数,啥也不会),上面的调用也可以写成这样:

getNumFn().then(
  res => {
    console.log(res);
  },
  err => {
    console.log(err);
  }
)

这时就简单达到跟catch一样的效果了。但实际上,在执行resolve的回调时,如果抛出异常了/代码报错了,那么就会卡死,这时catch就显得不可缺少了:

// 这里是没有catch,代码会报错,控制台会出现红色的提示 后面又操作也不会继续执行
getNumFn().then(
  res => {
    console.log(num); // 未定义的num,会报错
    console.log(res);
  },
  err => {
    console.log(num); // 未定义的num,会报错
    console.log(err);
  }
)

// 写上catch之后
getNumFn().then(
  res => {
    console.log(num);
    console.log(res);
  },
  err => {
    console.log(num);
    console.log(err);
  }
).catch(err => {
  console.log("有错误", err);
  // 后面有操作可继续执行
  console.log(123); // 会执行
})
// 控制台的错误提示不会显示为红色

catch方法会把错误原因传到err这个参数中,即便有代码也不会报错,与try/catch语句有相同的功能。

finally

finally方法,这个方法不接受任何参数,但是可以在回调函数中访问之前Promise的解决值或拒绝原因,无论 Promise 的状态如何,最终操作的消息都将打印到控制台。

// 简单拿上面获取随机数函数调一下 (很少用到)
getNumFn().finally(() => {
  console.log("我都会执行");
})

all的用法

all方法,是在所有异步操作都执行完之后才执行回调:

function p1() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("第一次请求");
      resolve("操作1");
    }, 1000)
  })
}

function p2() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("第二次请求");
      resolve("操作2");
    })
  }, 500)
}

function p3() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("第三次请求");
      resolve("操作3");
    }, 100)
  })
}

Promise.all([ p1(), p2(), p3() ]).then(res => {
  console.log(res);
})

// 执行结果为:
// 第二次请求
// 第三次请求
// 第一次请求
// ["操作1", "操作2", "操作3"]

all方法接收一个数组参数,里面的值最终都算返回Promise对象。这样就算异步操作是并行执行的,all也会等他们全部执行完,才会进入then里面,三个异步操作的数据都被all放到一个数组中了。

race的用法

all方法和race方法区别在于:all全部执行完再执行回调,race一个执行完就执行回调

// 函数还是用上面的 p1、p2、p3
Promise.race([ p1(), p2(), p3() ]).then(res => {
  console.log(res);
})
// 执行结果:
// 第二次请求
// 操作2 // 这是 Promise.race的执行结果
// 第三次请求
// 第一次请求

总结

Promise不止这些,还有async await语法糖。

看一遍,实际用一遍,你就会了;学吧,学到了都是你自己的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/694388.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

爬虫如何通过HTML和CSS采集数据的 ?

爬虫可以应用于各种应用场景&#xff0c;包括数据分析、市场研究、舆情监测、竞争报、价格比较、内容聚合等。对于需要大量数据的业务和研究领域&#xff0c;爬虫能够提供宝贵的支持。 爬虫可以按照设定的规则从多个网进行批量数据抓取&#xff0c;比人工手动方式更高效。量数据…

什么是DevOps

什么是DevOps 1.概述附录 1.概述 >什么是DevOps与CICD 附录 1.什么是DevOps

【Leetcode】19.删除链表的倒数第 N 个结点

一、题目 1、题目描述 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例1: 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]示例2: 输入:head = [1], n = 1 输出:[]示例3: 输入:head = [1,2], n = 1 输出:[1]提示: 链表中结点的数目为 sz…

通付盾升级数信云4.0,利用人工智能、区块链及Web3安全技术助力数据要素市场化

数据作为新型生产要素已成为数字时代的核心生产力。人工智能、区块链、云计算等新兴技术提升了数据要素的使用效率&#xff0c;开启数字化浪潮。但同时&#xff0c;以“数据上云”为代表的数据应用趋势也带来了数据安全、数据隐私和数据共享难等一系列阻碍数据要素化的问题。20…

excel相关操作

文章目录 1、数据分列与绘图1.1、杂乱的数据拷贝到excel1.2、 智能分列1.2 或者手动设置分列1.3、杂论的符号替换掉1.4、对时间再次只能分裂1.5、绘图 1、数据分列与绘图 1.1、杂乱的数据拷贝到excel 1.2、 智能分列 选择数据&#xff0c;数据–>分列–> 智能分列 结…

多服务器云探针源码(服务器云监控)

全球服务器分布世界地图 服务器&#xff08;控制端&#xff09; ping 连通率功能 后台编辑 添加 删除 服务器&#xff08;控制端&#xff09; 生成服务器&#xff08;控制端&#xff09;一键安装脚本 在线 SSH 多服务器批量执行命令 多服务器定制分享地址 控制游客那些服…

汽车行业app开发,汽车保养APP开发需要多少钱?

在现代社会&#xff0c;随着科技的快速发展&#xff0c;手机APP已经成为了我们生活中不可或缺的一部分&#xff0c;从旅游预订、餐饮外卖到汽车保养&#xff0c;各种行业都在尝试通过APP来提供更方便、更个性化的服务。对于汽车行业而言&#xff0c;一款优质的汽车保养APP不仅能…

计算机组成原理(期末或考研备考)-计算机性能指标(字长,主存容量,吞吐量,主频和时钟周期)

字长&#xff1a;字长是指计算机进行一次整数运算所能处理的二进制数据的位数&#xff0c;通常与CPU寄存器大小相同&#xff0c;因为数据进入到CPU之前会放入寄存器中。 主存大小&#xff1a;通常使用字数字长&#xff0c;例如512K*16位就表示共有512K个存储单元&#xff0c;每…

回归预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU多变量回归预测

回归预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU多变量回归预测 目录 回归预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU多变量回归预测效果一览基本描述程序设计参考资料 效果一览 基本描述 1.Matlab实现QPSO-BiGRU、PSO-BiGRU和BiGRU双向门控循环单元多变量回归…

Win11转移conda环境——从C盘转移到D盘

原本就是将Anaconda安装到了C盘&#xff0c;结果发现环境他还是默认安装到了C盘&#xff0c;就打算再转移一下 conda版本为 首先找到Win11下面的环境位置 C:\Users\用户名\.conda\envs比如我的就是 C:\Users\Arona\.conda\envs找到D盘安装Anaconda的位置 D:\ProgramData\an…

vue项目系统内路由无权限跳转404改为跳转401

当客户进入新页面无权限时,打开一个新页签,提示客户“sorry! 你没有权限去该页面” 。系统外路由还是跳转404. 解决思路: 这里需要后端提供个接口,传当前路由,如果是系统内路由接口返回true,如果不是返回false. 在路由跳转404的时候进行调接口判断。如果返回true .则跳…

数字化转型|银行业数据中心数字化转型之模型篇 02

导语&#xff1a; 银行业数据中心数字化转型是一项系统性工程&#xff0c;既涉及管理层面转型——包括数字化转型战略、基础架构和技术架构转型、技术创新和知识体系转型&#xff0c;又涉及执行层面转型——包括人员管理&#xff08;P&#xff09;、流程管理&#xff08;P&…

CAD Voronoi 3D三维泰森多边形维诺图插件三维狄利克雷镶嵌(Dirichlet tessellation)

三维Voronoi Voronoi又名泰森多边形或Dirichlet图、维诺图等&#xff0c;三维Voronoi是由连接两邻点直线的垂直平分面组成的连续三维多面体结构。Voronoi在各个学科中应用广泛&#xff0c;如进行区域规划、晶体塑性有限元研究、路径优化、地形简化、多孔结构力学等方面的分析。…

PSD笔记

在实际应用中&#xff0c;一个信号我们不可能获得无穷长时间段内的点&#xff0c;对于数字信号&#xff0c;只能通过采样的方式获得N个离散的点。上文提到&#xff0c;实际信号基本上是随机信号&#xff0c;由于不可能对所有点进行考察&#xff0c;我们也就不可能获得其精确的功…

DETR:End-to-End Object Detection with Transformers笔记

文章目录 End-to-End Object Detection with Transformers摘要本文方法损失函数 代码实现 End-to-End Object Detection with Transformers 摘要 提出了一种将目标检测视为直接集预测问题的新方法。我们的方法简化了检测管道&#xff0c;有效地消除了许多手工设计的组件&…

Win10实时保护老是自动开启怎么办?

Win10实时保护老是自动开启怎么办&#xff1f;使用Win10电脑的用户遇到了实时保护老是自动开启的问题&#xff0c;想知道怎么操作才能解决此问题&#xff0c;这时候用户需要打开电脑的组策略编辑器&#xff0c;然后找到管理模板中的Windows Defender选项&#xff0c;点击关闭Wi…

Intellij IDEA HTTP Request 请求设置Cookie

使用Intellij IDEA 的 HTTP Request 请求中带有Cookie时&#xff0c;需要将 Cookie单词要写成全小写的“cookie”&#xff0c;否则设置的Cookie不会生效。 POST http://localhost:9091/rest/miracle/findList Content-Type: application/json cookie: JSESSIONIDce22a4ed-b185…

Redis基本数据类型

string&#xff08;字符串&#xff09;&#xff1a;最常见的用户是缓存用户信息&#xff0c;将用户信息结构体使用JSON序列化成字符串&#xff0c;然后将序列化后的字符串塞进Redis来缓存&#xff0c;然后取用户信息的过程会经历一次反序列化的过程。 Redis的字符串是动态字符…

互联网+洗鞋店预约小程序新模式;

互联网洗鞋店预约小程序 1、线上线下业务的结合。 传统的线下业务消费者到店可以向其推介线上的预约到家服务&#xff0c;让线下的消费者成为小程序内的会员&#xff0c;留存客户之后线上可直接触达&#xff0c;减少与消费者的距离&#xff0c;从等待客户到可以主动出击&…

Mac 配置Flutter开发环境遇到的坑

1. flutter doctor 命令无反应; 加sudo 执行; sudo flutter doctor执行完后, 在执行flutter doctor就好使了, 就很神奇;(还不行就重启再试试) 2. 创建项目提示没权限, 照提示命令赋予权限即可;(应该是前面sudo命令引起的, 但没找到其他好办法) 最后一个提示的没权限, 照提示运…