当前位置: 首页 > 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.lryc.cn/news/593224.html

相关文章:

  • Node.js:Stream、模块系统
  • 鸿蒙与web混合开发双向通信
  • Linux:多线程---深入生产消费模型环形队列生产消费模型
  • Nestjs框架: RxJS 核心方法实践与错误处理详解
  • 告别项目混乱:基于 pnpm + Turborepo 的现代化 Monorepo 工程化最佳实践
  • win10连接鼠标自动关闭触摸板/win10关闭触摸板(笔记本)
  • 深度学习图像分类数据集—六十种植物病害分类
  • ABP VNext + Temporal:分布式工作流与 Saga
  • install_arm_docker.sh
  • Django接口自动化平台实现(三)
  • Django母婴商城项目实践(八)- 数据渲染与显示之首页
  • LLM 的Top-P参数 是在LLM中的每一层发挥作用,还是最后一层?
  • 【设计模式C#】外观模式(用于解决客户端对系统的许多类进行频繁沟通)
  • Django母婴商城项目实践(七)- 首页数据业务视图
  • 洛谷 P2947:[USACO09MAR] Look Up S ← 数组模拟+单调栈
  • 使用 Gunicorn 部署 Django 项目
  • 5 基于STM32单片机的绝缘检测系统设计(STM32代码编写+手机APP设计+PCB设计+Proteus仿真)
  • 6 STM32单片机的智能家居安防系统设计(STM32代码+手机APP设计+PCB设计+Proteus仿真)
  • 对话访谈 | 盘古信息×锐明科技:中国企业高质量出海“走进去”和“走上去”
  • 家庭KTV v1.1.9 | 曲库丰富,无限制免费K歌
  • 驾驭 Spring Boot 事件机制:8 个内置事件 + 自定义扩展实战
  • 《一行注解解决重复提交:Spring Boot 接口幂等实战》
  • 深入理解设计模式:策略模式的艺术与实践
  • 在非Spring Boot的Spring项目中使用Lock4j
  • 用graphviz画一个关系图
  • 云服务器磁盘IO性能优化的测试与配置方法
  • 2025年7月19日,二维矩阵
  • 智能制造——解读39页汽车行业数字化工厂解决方案【附全文阅读】
  • 异世界历险之数据结构世界(二叉树-leetcode)
  • 国产电科金仓数据库:融合进化,智领未来