当前位置: 首页 > news >正文

Promise入门

文章目录

  • 为什么使用Promise
  • Promise介绍


为什么使用Promise

在ES5中使用回调函数来处理异步任务,当多个异步任务有依赖关系时(如下定时器的层层嵌套),就需要回调函数互相嵌套,当嵌套结构多了后,就出现了回调地狱的问题,难以维护

setTimeout(function () {console.log('a1');setTimeout(function () {console.log('a2');setTimeout(function () {console.log('a3');setTimeout(function () {console.log('a4');setTimeout(function () {console.log('a5');}, 1000);}, 1000);}, 1000);}, 1000);
}, 1000);

故在ES6中提供了Promise 对象,解决了以上问题,并统一了规范,提高了可读性等

Promise介绍

Promise有三种状态

  1. pending:等待中。属于初始状态,既没有被兑现,也没有被拒绝。
  2. fulfilled:已兑现/已解决/成功。执行了resolve() 时,立即处于该状态,表示 Promise已经被解决,任务执行成功
  3. rejected:已拒绝/失败。执行了 reject()时,立即处于该状态,表示 Promise已经被拒绝,任务执行失败。
    Promise构造函数如下
// 1. 定义 executor 函数
function executor(resolve, reject) {setTimeout(() => {resolve("foo");}, 300);
}// 2. 把 executor 传入 Promise 构造函数
const promise1 = new Promise(executor);//使用箭头函数则是
const promise1 = new Promise((resolve, reject) => {setTimeout(() => {resolve("foo");}, 300);
});

此处的resolve reject是形参,可以任意命名,但通常以此命名
而executor 的函数体(第一个箭头函数的函数体)中负责启动异步任务,并在恰当的时机调用resolvereject
如下

const coinPromise = new Promise((resolve, reject) => {setTimeout(() => {if (Math.random() < 0.5) {resolve(1);} else {reject('error');}}, 0);
});// 使用
coinPromise.then(val => console.log(val))   // 可能输出 1.catch(err => console.log(err)); // 可能输出 error

then和catch也可以这样写

promise.then(onFulfilled).catch(onRejected);//这是上面的结构
//等价
promise.then(onFulfilled, onRejected);

如上是一个50%的概率输出1或error的promise实例
可以看出调用的resolve()的参数1会被then中匿名箭头函数的参数val接收,同理,error对应err
并且promise的状态一旦改变,则确定了下来,不可逆,
执行机制如图
在这里插入图片描述

而then 方法返回一个新的 Promise,从而允许链式调用。(then返回的对象状态为待定,与当前的Promise的状态无关)
then其中的匿名箭头函数的返回值会被then捕获成为其新的Promise的返回值
故开头的回调可以如下修改

// 1. 先把 setTimeout 包装成返回 Promise 的工具
//计时不需要判断成功与失败,故只传resolve,构造体为setTimeout(resolve, ms)
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));// 2. 链式写法,彻底消灭回调地狱
delay(1000).then(() => { console.log('a1'); return delay(1000); })//执行完‘ai’后会成为新的delay(1000).then(() => { console.log('a2'); return delay(1000); }).then(() => { console.log('a3'); return delay(1000); }).then(() => { console.log('a4'); return delay(1000); }).then(() => { console.log('a5'); });

上面的链式结构没有匿名函数的参数,可以使用n记录层数作为参数

const delay = (ms, value) =>new Promise(resolve => setTimeout(() => resolve(value), ms));// 从 0 开始,逐层+1  n会接收resolve的value
delay(1000, 0)               // 第 0 层.then(n => { console.log('a' + n); return delay(1000, n + 1); }) // 0 → 1.then(n => { console.log('a' + n); return delay(1000, n + 1); }) // 1 → 2.then(n => { console.log('a' + n); return delay(1000, n + 1); }) // 2 → 3.then(n => { console.log('a' + n); return delay(1000, n + 1); }) // 3 → 4.then(n => { console.log('a' + n); });                          // 4 → 5

如下,是抛硬币的层层嵌套,连续5次成功才会正常结束

const flip = () =>new Promise((resolve, reject) => {setTimeout(() => {if (Math.random() < 0.5) {resolve('success');} else {reject('error');}}, 0);});flip().then(() => { console.log('成功'); return flip(); }).then(() => { console.log('成功'); return flip(); }).then(() => { console.log('成功'); return flip(); }).then(() => { console.log('成功'); return flip(); }).then(() => { console.log('finally成功'); }).catch(() => { console.log('失败'); });

其中的return flip();匿名箭头函数的返回值会被then捕获成为其新的Promise的返回值


不仅如此
resolve()的参数不同,会决定对应的Promise的状态

  1. 如果resolve()中传入普通的值或者普通对象(包括 undefined),那么Promise 的状态为fulfilled。这个值会作为then()回调的参数。这是最常见的情况
  2. 如果resolve()中传入的是另外一个新的 Promise,那么原 Promise 的状态将交给新的 Promise 决定。
  3. 如果resolve()中传入的是一个对象,并且这个对象里有实现then()方法(这种对象称为 thenable 对象),那就会执行该then()方法,并且根据then()方法的结果来决定Promise的状态。

此处暂不涉及

故有了promise就可以更简单的处理回调函数的嵌套问题

http://www.dtcms.com/a/288056.html

相关文章:

  • 三级知识点汇总(详解)【c++】——2
  • 我用Cursor,1周上线了一个虚拟资料流量主小程序技术选型
  • Linux“一切皆文件“设计哲学 与 Linux文件抽象层:struct file与file_operations的架构解析
  • 【ChatOpenAI】常用方法详解
  • HOT100——动态规划篇Leetcode221. 最大正方形
  • C++ std::thread线程类 相关问题、函数总结
  • 单调队列深度解析(下)
  • 如何解决 ‘NoneType‘ object has no attribute ‘get‘问题
  • GA-BP遗传算法优化BP神经网络数据生成,采用SVM分类模型评估
  • LM317 芯片推荐电路中保护二极管工作原理
  • 教育科技内容平台的用户定位与产品方案:从需求到解决方案的精准匹配
  • prometheus UI 和node_exporter节点图形化Grafana
  • GaussDB 数据库架构师修炼(六) 集群工具管理-1
  • 农经权二轮延包—批量出图片
  • 了解.NET Core状态管理:优化技巧与常见问题解决方案
  • 第4章 数据的排序、筛选和分类汇总
  • 金融系统AIGC能力中心赋能实战指南
  • 告别 T+1!解密金融级实时数据平台的构建与实践
  • RK3568 Linux驱动学习——SDK安装编译
  • 浅谈Rust语言特性
  • [C/C++安全编程]_[中级]_[如何避免出现野指针]
  • MySQL 写入性能优化全攻略(附 GitHub 面试题项目链接)
  • 相机参数的格式与作用
  • 大语言模型置信度增强实战指南
  • 第 3 篇:《WHERE 就是刷选项——像点外卖一样精确筛房!》
  • 【硬件】嵌入式问题
  • FPGA相关通信问题详解
  • XSS漏洞总结
  • 商业秘密视域下计算机软件的多重保护困境
  • 正点原子stm32F407学习笔记9——PWM 输出实验