Promise及相关知识细学

news2024/9/22 13:40:51

学习关键语句:
Promise
promise学习
promise.all
promise.race
promise.resolve

1. 写在前面

promise 是前端绕不开的东西 , 所以我们一定要好好学习 , 写这篇文章的目的是加深对 promise 的学习和使用程度

2. 开始

2.1 准备

首先创建一个文件夹 , 里面新建一个 index.html 和 index.js
我们在浏览器环境观看 promise 的使用效果
在这里插入图片描述

2.2 看

我们要先看一看这个 promise 到底是啥

let o1 = new Object()
console.log(o1)

let p1 = new Promise((resolve, reject) => { })
console.log(p1)

我们可以看到 promise 比正常的对象要多了两个东西 , 一个是 PromiseState , 值为 pending ; 一个是 PromiseResult , 值为 undefined

在这里插入图片描述

我们从实例化方式和打印对象中可以看出 , promise 是一个构造函数或者说类 , 看上去只不过是在实例化时传入一个函数而已 , 那么我们继续看一看一个简单的 promsie 例子后 , 我们再看这个 promise 变成什么了

let x = 1
let p1 = new Promise((resolve, reject) => {
  if (x < 2) {
    resolve(x)
  } else {
    reject(x)
  }
})
p1.then(value => {
  console.log('value:' + value) // value:1
}, reason => {
  console.log('reason:' + reason)
})
console.log(p1)

我们看到 PromiseState 变成了 fulfilled 而 PromiseResult 变成了 1

在这里插入图片描述

这好像没什么大不了的嘛 , 乍一看就跟乍一看一样 , 好像理所当然应该是这样的

接下来我们将 prototype 点开 ,看一看原型上有哪些方法

在这里插入图片描述

原型上的方法不多嗷 , 我们也只需要关注 catch finally 和 then 方法就够了
ok 那么我们已经完全看到了 promise 实例的相关内容 , 接下来我们来看一看 promise 构造器上有什么内容
点开 constructor

在这里插入图片描述

构造器上的方法我们需要关注的就是 all allSettled any race reject 和 resolve 方法

好啦 , 这下 promise 已经被你完全看完了 , 到这里大致混个眼熟就 ok , 接下来才开始学习

2.3 基础知识

可能你会有所疑惑 , 所以接下来介绍一下基础知识

一、PromiseState

一个 promise 有三个状态 , 分别是 pending , fulfilled 和 rejected

  1. pending 是一个 promise 的基础状态 , 所有 promise 一开始都是 pending 状态
    理解为 一个承诺即将发生
  2. fulfilled 表示这个 promise 已完成并且执行成功的回调函数
    理解为 一个承诺守约履行了
  3. rejected 表示这个 promise 失败了并且执行失败的回调函数
    理解为 一个承诺毁约拒绝了

特别注意:

  • 一个 promise 只能有一个状态 , 即一个承诺不会 即将发生 \ 守约 \ 毁约 同时出现
  • 状态 能从 pending 向 fulfilled rejected 改变
  • 状态一旦发生改变 , 将不会发生第二次改变 , 即状态固化了

二、PromiseResult

顾名思义 , 其实指的就是一个 promise 的结果值

  • 承诺守约履行了值就为 成功回调传入的参数
  • 承诺毁约拒绝了值就为 失败回调传入的参数
  • 由于状态不会发生二次改变 , 所以结果值是不会变的 , 无论多少次调用都会是同一结果

三、promise中的两个参数函数

我们看以下代码

let x = 1;
let p1 = new Promise((resolve, reject) => {
  if (x < 2) {
    resolve(x);
  } else {
    reject('出错了');
  }
});

p1 是我们新实例化的一个 promise 对象 , 和正常实例化一样的是 , 我们在初始化时传递了一个参数进去 , 只不过这个参数是一个函数 , 喏就是下面这个函数 , 是不是这样看起来就好很多

(resolve, reject) => {
  if (x < 2) {
    resolve(x);
  } else {
    reject('出错了');
  }
}

这个函数一共有两个参数 , resolve 和 reject , 而这两个参数恰好又是两个函数 , 只不过这两个函数不是我们定义的 , 我们在这里写的 resolve 和 reject 只是两个形参 , 你可以随便改名 , 叫啥都行

在 promise 的构造器中会自动调用我们传入的这个函数 , 同时会将真正的实参函数 resolve 和 reject 传入进来

而在我们的函数体中 , 当我们想要 履行承诺 时就调用 resolve 方法 , 并且将想要传递的值作为参数放入 ; 想要 拒绝承诺 时就调用 reject 方法 , 并且将拒绝的理由作为参数放入 ; 而无论是成功还是失败 , 我们放入的参数都会成为最终的 PromiseResult

同时 , 刚刚才学过的 PromiseState 知识告诉我们 , 我们调用 resolve 方法后状态就会从 pending 变成 fulfilled , 调用 reject 方法后状态就会从 pending 变成 rejected

你可以看到在我们上面的代码中 , x = 1 , 所以 x < 2 是成立的我们想要的结果 , 那么我们就 履行承诺 调用resolve 方法并且把 x 传入同时状态变成了 fulfilled , 否则呢我们就 拒绝承诺 调用 reject 方法并且把我们的拒绝理由 出错了 传入同时状态变成了 rejected

总的来说就是 , 这两个参数函数和我们无关 , 我们只要达到目的的时候调用一下就可以了

2.4 promise 的原型方法

好了 , 基本上已经了解的差不多了 , 接下来我们说说原型上的方法

2.4.1 then() 方法

首先我们要先弄清楚什么叫履行承诺 , 什么叫拒绝承诺

第一步是我给出承诺 , 如果我履行就干嘛干嘛 , 如果我拒绝就怎样怎样

第二步是你看我的行为 , 我到底是履行了还是拒绝了 , 我履行了你就怎样怎样 , 我拒绝了你就干嘛干嘛

其实就是一个根据上一个行为做出下一个行为

我们来看以下代码

let x = 1
let p1 = new Promise((resolve, reject) => {
  if (x < 2) {
    resolve(x)
  } else {
    reject('出错了')
  }
})
p1.then(value => {
  console.log('value:' + value)
}, reason => {
  console.log('reason:' + reason)
})

在这段代码的使用过程中呢 , 我们可以看到 then() 方法接收两个参数 , 而第一个参数就是成功的回调 , 当一个 promise 使用 resolve 方法时 , then() 方法就会进入第一个参数函数 , 同时将 resolve 方法中的参数传入 ;
当一个 promise 使用 reject 方法时 , then() 方法就会进入第二个参数函数 , 同时将 reject 方法中的参数传入

上面的代码中 , 我们调用的是 resolve 方法 , 所以 x 作为参数传到了第一个函数中替代了 value 形参 , 所以就打印了 value: 1

同样的如果将上面代码中的 x 修改为 10 , 就会调用 reject 方法 , 出错了 三个字就会作为参数传到第二个函数中替代 reason 形参 , 打印出 reason: 出错了

这就是 then() 方法了 , 是不是又简单又好用

2.4.2 catch() 方法

我们已经了解到了简单好用的 then() 方法 , 但是我还是觉得一个参数中写两个函数很难受 , 别问问就是难受 , 那怎么办呢

那当然就看看 catch() 方法了 , 我们来看以下代码

let x = 10
let p1 = new Promise((resolve, reject) => {
  if (x < 2) {
    resolve(x)
  } else {
    reject('出错了')
  }
})
p1.then(value => {
  console.log('value:' + value)
}).catch(err => {
  console.log('err:' + err)
})

可以看到 , 在 then() 中我只写了一个参数函数 , 那么按理说我们应该获取不到拒绝承诺的结果的 , 但是我们在后面又补上了一个 catch() 方法 , 同时 catch() 方法中的参数也是一个函数 , 所以 catch() 方法就是专门用来捕获拒绝的承诺 , 这样相比在 then() 中写两个函数要清晰明了很多 , 我们看看控制台中打印了什么

在这里插入图片描述

当然了 , 你可能会问 , 那我都写呗 , 当然没问题啦 , 只不过都写的话 , catch() 方法就会失效

let x = 10
let p1 = new Promise((resolve, reject) => {
  if (x < 2) {
    resolve(x)
  } else {
    reject('出错了')
  }
})
p1.then(value => {
  console.log('value:' + value)
}, reason => {
  console.log('reason:' + reason)
}).catch(err => {
  console.log('err:' + err)
})

在这里插入图片描述

所以可以认为 catch() 方法是 then() 方法的语法糖 , 当正主出来的时候 , 替身自然就要下场了

注意
你可能已经注意到了 , 在上面的代码中 , 我们是在 then() 方法的末尾直接使用点语法调用的 catch() 方法 , 因此我们意识到每个方法都会返回一个新的 promise , 这样才能达到不断链式调用的效果

2.4.3 finally() 方法

顾名思义啊 , 这个 finally() 方法呢就是最后执行的方法 , 而且是无论如何都会执行的方法 , 不接收参数

let x = 10
let p1 = new Promise((resolve, reject) => {
  if (x < 2) {
    resolve(x)
  } else {
    reject('出错了')
  }
})
p1.then(value => {
  console.log('value:' + value)
}).catch(err => {
  console.log('err:' + err)
}).finally(a => {
  console.log('finally:', a)
})

在这里插入图片描述

我们看到 finally 打印出来的 a 是 undefined , 所以 finally() 方法是没有参数的 , 而且一定会执行

注意
finally() 方法也会返回一个新的 promise , 所以同样可以链式调用

p1.then(value => {
 console.log('value:' + value)
}).finally(a => {
 console.log('finally:', a)
}).catch(err => {
  console.log('err:' + err)
})

2.5 Promise 的静态方法

前面需要学习的原型方法就是那三个啦 , 接下来学习一下静态方法 , 也就是使用 static 声明在类中的方法

2.5.1 Promise.resolve() 方法

静态方法的话呢我觉得还是从 Promise.resolve() 方法开始学起最为简单 , 因为他的功能最简单

效果 : 将参数包装为 promise 对象

当然了 , 这里的参数需要分情况处理

  1. 参数为 promise 对象

    如果参数本身就已经是一个 promise 对象了 , 那就原封不动的返回这个 promise 对象

    let p1 = new Promise((resolve, reject) => { });
    let p2 = Promise.resolve(p1);
    console.log(p1 === p2); // true
    
  2. 参数是普通数据

    参数是数字 , 字符串 , 布尔值 , undefined , null , 数组 , 对象 , Set , Map 时则返回一个新的Promise对象,且 PromiseState 状态为 fulfilled , PromiseResult 值为参数值

    console.log(Promise.resolve(123))
    console.log(Promise.resolve('shaoyahu'))
    console.log(Promise.resolve(false))
    console.log(Promise.resolve(undefined))
    console.log(Promise.resolve(null))
    console.log(Promise.resolve([1, 3]))
    console.log(Promise.resolve({ name: 'shaoyahu' }))
    console.log(Promise.resolve(new Set([1, 2])))
    console.log(Promise.resolve(new Map([[1, 1], [2, 2]])))
    

    在这里插入图片描述

  3. 没有参数

    没有参数就直接返回一个空值的 promise

    let p1 = Promise.resolve()
    let p2 = Promise.resolve(undefined)
    console.log(p1)
    console.log(p2)
    console.log(p1 === p2)
    

    在这里插入图片描述

2.5.2 Promise.reject() 方法

用法和 Promise.resolve() 方法一样 , 只不过返回值的状态为 rejected , 其他没有区别

2.5.3 Promise.all() 方法

效果 : 对多个原有的 promise 包装进一个新的 promise 中 , 而这个新的 promise 只有 所有的 promise 全部状态变为 fulfilled 或者 任意一个 promise 状态变为 rejected 时才会从 pending 状态变为相应的状态

all() 方法接收的参数是一个数组 , 将所有的 promise 对象放在数组中 , 如果出现不是 promise 对象的参数 , 则默认使用 Promise.resolve() 方法进行包裹

简单来说就是所有的 promise 成功就成功 , 有一个失败就失败 , 我们看以下代码

let p1 = new Promise((resolve, reject) => {
  resolve('p1')
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2')
  }, 2000);
})
let p3 = new Promise((resolve, reject) => {
  resolve('p3')
})
let p = Promise.all([p1, p2, p3, 123])
console.log(p)
p.then(value => {
  console.log(value)
  console.log(p)
})

我们来看看结果 , 很显然 , 一开始 p 是处于 pending 状态的 , 等数组中所有的 promise 都返回成功之后才改变为 fulfilled 状态 , 并且返回值是每个 promise 返回值组成的数组

在这里插入图片描述

如果有一个 promise 失败了 , 那么返回的就会是 rejected 状态的 p , 同时返回值是失败的那个 promise 的失败原因

2.5.4 Promise.race() 方法

这个方法和 all() 方法其实差不多 , 只不过你看名字是 race , 竞速嘿嘿

效果 : 将多个 promise 实例 , 包装成一个新的 promise 实例 , 一旦迭代器中的某个 promise 成功或者失败 , 那么新的 promise 就会立即成功或者失败

简单来说就是只取返回最快的值,无论是成功还是失败 , 我们看以下代码

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p1')
  }, 1500);
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2')
  }, 2000);
})
let p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3')
  }, 1000);
})
let p = Promise.race([p1, p2, p3])
console.log(p)
p.then(value => {
  console.log(value)
  console.log(p)
})

我们从代码中可以看出 , 最快的应该是 p3 , 所以结果肯定就是 p3 了

在这里插入图片描述

2.5.5 Promise.any() 方法

效果 : 对多个原有的 promise 包装进一个新的 promise 中 , 原有的 promise 中一旦有一个成功了 , 就返回成功的那个 promise 值, 并且新的 promise 状态改为 fulfilled

简单来说 , 就是 Promise.all() 方法的眼瞎版 , 不用看失败的只看成功的 , 是 Promise.race() 方法的偏心版 , 我只拿第一个 , 但是我只看成功的 , 我们看以下代码

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p1')
  }, 1500);
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2')
  }, 2000);
})
let p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p3')
  }, 1000);
})
let p = Promise.any([p1, p2, p3])
console.log(p)
p.then(value => {
  console.log(value)
  console.log(p)
})

p3 是最快的 , 但是它是失败的 , 所以返回值是最快成功的 p1

在这里插入图片描述

2.5.6 Promise.allSettled() 方法

效果 : 对多个原有的 promise 包装进一个新的 promise 中 , 当所有的 promise 状态都发生改变时 , 新的 promise 状态改为 fulfilled , 并且返回值是原有 promise 返回值组成的数组加工后的值

简单来说 , 就是 Promise.all() 方法忽略了失败 , 将所有的结果都返回过来 , 我们看以下代码

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p1')
  }, 1500);
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2')
  }, 2000);
})
let p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p3')
  }, 1000);
})
let p = Promise.allSettled([p1, p2, p3])
console.log(p)
p.then(value => {
  console.log(value)
  console.log(p)
})

我们直接看返回数据 , 你一下就会懂了 , 很清晰的

在这里插入图片描述

3. 总结

Promise 作为前端必须要学习的一个重要知识点 , 想必大家上面的内容其实都会吧 , 我真是班门弄斧啊 , 那么之后 , 我们来重写一个 promise 类试试看吧

4. 结束

学到这里 , 终于可以松一口气了 , 怎么样 , 是不是已经完全掌握了呢 ?
其实还是挺有难度的 , 难度在真正用起来可能会比较绕 , 但是方法就这些 , 除非你只是在调用接口

如果你跟着做遇到了什么问题无法实现 , 请在评论区或者私信告诉我 , 我发动网友给你解答

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

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

相关文章

Navicat 16 支持 Redis Cluster 集群模式 | 新功能 √

Redis Cluster 适用于需要处理大量数据和高并发访问&#xff0c;并且需要保证高可用性和可扩展性的场景。它在国内许多行业中都得到了广泛的应用。为了满足广大专业用户的需求&#xff0c;Navicat 16 再次升级&#xff0c;新增 Redis Cluster 功能&#xff0c;为Redis 用户带来…

FreeRTOS 计数型信号量 详解

目录 什么是计数型信号量&#xff1f; 计数型信号量相关 API 函数 1. 创建计数型信号量 2. 释放二值信号量 3. 获取二值信号量 计数型信号量实操 什么是计数型信号量&#xff1f; 计数型信号量相当于队列长度大于1 的队列&#xff0c;因此计数型信号量能够容纳多个资源&a…

探索JavaScript ES6+新特性

JavaScript是一门十分流行的编程语言&#xff0c;它不断发展演变以适应现代Web开发需求。ES6&#xff08;也称为ECMAScript 2015&#xff09;是JavaScript的第六个版本&#xff0c;引入了许多令人兴奋的新特性和语法糖。本文将介绍一些ES6中最有趣和实用的特性。 箭头函数 箭…

【人脸检测 FPS 1000+】ubuntu下libfacedetection tensorrt部署

TensorRT系列之 Windows10下yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov7 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov6 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov5 tensorrt模型加速…

解决问题:Expected one result (or null) to be returned by selectOne(),but found: 2]

在做一次数据迁移后&#xff0c;系统登录失败&#xff0c;日志报错&#xff1a; 原因&#xff1a;在数据迁移账号时&#xff0c;用户账号有两个相同的账号&#xff0c;所以导致登录失败。

成功项目经理总结的20个项目管理经验

大家好&#xff0c;我是老原。 有人说&#xff1a;项目管理是变理想为现实&#xff0c;化抽象为具体的一门科学和艺术。 这是对项目管理的一种精辟总结。项目管理专业的方法和知识能教会我们如何快捷、科学、艺术地做事。 因为它除了交付项目&#xff0c;更能管理人生。 毕…

代码随想录 | Day56

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 今日学习目标一、算法题1.最长公共子序列2.不相交的线3.最大子数组和 今日心得学习及参考书籍 今日学习目标 最长公共子序列&#xff08;1143&#xff09; 不相交的…

数据结构与算法—栈

目录 一、栈的概念及结构 二、栈的实现 1、声明栈结构体 2、初始化 3、 销毁 4、 入栈&#xff08;压栈&#xff09; 5、出栈&#xff08;弹栈&#xff09; 6、栈的大小 OJ练习 完整版&#xff1a; Stack.h声明 Stack.c函数 test.c参考测试用例 一、栈的概念及结构…

CLIP系列:CLIP:沟通文本和图像的桥梁

CLIP沟通文本和图像的桥梁。 SOTA的视觉任务模型需要固定的监督数据对&#xff0c;比如-大象&#xff0c;-兔子。这种方式在特定数据集上能够拥有很好的性能&#xff0c;但是在其他未知类别上的性能就会急剧下降。这种监督形式限制了模型的通用性&#xff0c;因为需要额外的数据…

linux配置静态路由

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言硬件&操作系统一、静态路由是什么&#xff1f;二、开始配置1.netplan2.NetworkManager1.CLI2.Desktop 三、开始测试总结 前言 最近有一个需求&#xff0c;…

C++数据结构X篇_23_快速排序(最快、不稳定的排序)

文章参考十大经典排序算法-快速排序算法详解进行整理补充。快速排序是最快的排序方法。 排序思路&#xff1a;分治法-挖坑填数&#xff1a;大问题分解为各个小问题&#xff0c;对小问题求解&#xff0c;使得大问题得以解决 文章目录 1. 什么是快速排序1.1 概念1.2 算法原理1.3 …

淘宝商品链接获取淘宝商品评论数据(用 Python实现淘宝商品评论信息抓取)

在网页抓取方面&#xff0c;可以使用 Python、Java 等编程语言编写程序&#xff0c;通过模拟 HTTP 请求&#xff0c;获取淘宝多网站上的商品详情页面评论内容。在数据提取方面&#xff0c;可以使用正则表达式、XPath 等方式从 HTML 代码中提取出有用的信息。值得注意的是&#…

android10.0(Q)编译安卓内核(pixel 2)

下载内核源码 1.查看内核版本 首先需要看一下内核的版本&#xff0c;可以在手机中看到内核版本 2.下载该内核版本对应的源码 cd ~/mount/project/androidq git clone https://aosp.tuna.tsinghua.edu.cn/android/kernel/msm.git cd msm git checkout 4fecde07e68d执行结果如…

Python之作业(三)

Python之作业&#xff08;三&#xff09; 练习题 给出3个整数&#xff0c;使用if语句判断大小&#xff0c;并升序输出有一个列表lst [1,4,9,16,2,5,10,15],生成一个新列表&#xff0c;要求新列表元素是lst相邻2项的和随机生成100个产品ID&#xff0c;ID格式如下 顺序的数字6…

SD-WAN跨境网络专线|跨境访问无忧!让海外SaaS平台与视频会议更稳定轻松的解决方案

在现如今全球化的时代&#xff0c;企业都有布局全球或是有潜力的国家&#xff0c;在海外开分公司必不可少&#xff0c;那与海外合作伙伴进行沟通与合作已经成为企业的常态。但是&#xff0c;访问海外的SaaS平台和进行视频会议时&#xff0c;我们经常会遇到网络不稳定、速度慢的…

m1 安装 cocoapods

其实最终解决问题很简单&#xff0c;麻烦的是如果找到解决问题的答案。 网上的答案一大堆&#xff0c;但不一定适合你的电脑&#xff0c;就好像天下的女人到处有&#xff0c;但不一定都适合你&#xff0c;一定要亲自试验一下才知道结果。 前提条件&#xff1a; 命令行工具&am…

Dunham‘s sports EDI需求分析

Dunhams Sports&#xff0c;成立于1937年&#xff0c;是美国领先的运动用品零售商之一。公司总部位于密歇根州&#xff0c;致力于提供广泛的体育用品和户外装备。Dunhams Sports的使命是为顾客提供最优质的运动体验&#xff0c;他们以卓越的服务和品质&#xff0c;赢得了无数荣…

【访问控制】—>《熟练使用ACL进行上网行为管理》

✍ 标准和高级ACL功能介绍&#xff1b; ✍ 思科和华为ACL功能有什么区别&#xff1f; ✍ 现网中ACL都有哪些使用场景&#xff1f; -- ACL - 访问控制列表 - 控制&#xff1a; 能通/不能通 -- ACL - 结合功能 list - 简化版本的行为管理 -- 插件性质的功能 --…

echarts 仪表盘统计图

<!--仪表盘统计图--><div class"ybptx" ref"btryzb"></div>mounted(){this.getBtData();}getBtData() {let chart this.$echarts.init(this.$refs.btryzb);let data_czzf this.cznlzhpj.czzfs;let option {series: [{name: 内层数据刻…

水表能实时监测哪些参数?

你是否曾经想过&#xff0c;你家的水表是如何工作的?它不仅能够记录你的用水量&#xff0c;还能实时监测一些重要的参数&#xff0c;比如水压、水温、水质等。这些参数对于保证用水安全和节约用水资源都有着重要的作用。接下来&#xff0c;小编就来为大家详细的介绍下水表能实…