当前位置:   article > 正文

ES6 Promise(承诺)看这一篇就够了

es6 promise

目录

一、什么是promise

二、 Promise格式及PromiseState

(1)pending 

(2)fulfilled 或 resolved

(3)rejected

三、PromiseResult

 四、promise链式调用

五、回调地狱

错误写法

正确写法

实例中优化


一、什么是promise

我们通常都会去 new 一个Promise,什么东西可以new啊? 是不是构造函数可以new, 通过控制台dir一下Promise   

 通过上面的输出,你可以知道promise是一个构造函数,而上面常见的几个方法,resolve、reject、catch、resolve 你不需要立即知道它是干嘛的,接下来 听鹅说

 Promise是Es6新增的构造器,用来提优化异步代码的写法,Promise中文意为承诺,承诺它一段时间后返回给你最终的结果。

首先了解三个状态,用setTimeout模拟实现一个ajax

        pending===》resolve(fulfilled)

  1. let p1 = new Promise((resolve)=>{
  2. setTimeout(() => {
  3. resolve(1)
  4. }, 2000);
  5. })
  6. console.log(p1);

 pending===》rejcet(rejected)

  1. let p1 = new Promise((resolve,reject)=>{
  2. setTimeout(() => {
  3. reject(1)
  4. }, 2000);
  5. })
  6. console.log(p1);

三个状态

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled): 意味着操作成功完成。
  • 已拒绝(rejected): 意味着操作失败。

 举个栗子吧,小秃和小花去表白,小秃说 我喜欢你,你喜欢我吗? 这时候 小花肯定有两种回复 答应和拒绝

pedding:你可以理解为小秃正则等待小花的回复,但是目前没有回复的准确结果,例如上面代码的setTimeout 等待的2秒就是等待时间

fulfilled:  代表 我同意啦 我也暗恋你很久了! 

rejected: 代表 你不配 渣男!

二、 Promise格式及PromiseState

相信 我对上面的balabala 已经提取你学习promise的兴趣了,接下来进入正题 学习一下promise格式定义

  1. // 箭头函数
  2. let p1 = new Promise((resolve,reject)=>{})
  3. // 普通声明
  4. let p2 = new Promise(function (resolve,reject) {})

创建promise对象时,它的参数是一个函数 如果他会报错  Uncaught TypeError: Promise resolver undefined is not a function at new Promise (<anonymous>)

而这个函数中的两个形参(resolve,reject) 也是函数形式,但这两个只是形参的名字 实际上你写什么都可以,只不过我们通常约定 写着两个形参名

(1)pending 

pending:待定,是一个等待最终结果的状态,也是一个初始状态,如果你在函数中不调用resolve,reject最终都是一个一直等待的状态,但是不调用,并没有什么意义,一般常用与调用resolve、reject给与相应的状态,总结:你只需要知道这是一个等待最终结果的状态,至于之后会发生状态,并不会知道

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

(2)fulfilled 或 resolved

fulfilled代表已兑现、成功 ,意思是承诺兑现了 从pending====>fulfilled 的过程,在之前的浏览器版本可能会出现resolved的情况都是代表成功,当调用resolve函数时 就会进入成功(fulfilled )的状态

  1. let p1 = new Promise((resolve,reject)=>{
  2. resolve(1)
  3. })

PromiseState代表状态,PromiseResult 代表值 resolve、reject 调用时传入的数据

(3)rejected

rejected: 代表拒绝,失败,意思是承诺没有实现从pending=》rejected的过程  当调用 失败(reject)的状态

  1. let p1 = new Promise((resolve,reject)=>{
  2. reject(1)
  3. })

 小结 

最初创建对象的状态是pending     当调用了 resolve方法时 就会进入 fulfilled 状态         当调用reject方法 就会进入 rejected 状态

当状态一旦发送改变 就不会重新改变  例如已经从pending  到 fulfilled 了就不会重新改变到 rejected

  1. let p1 = new Promise((resolve,reject)=>{
  2. resolve()
  3. reject()
  4. })
  5. console.log(p1);

在上面的代码只会从 pending状态到fulfilled状态,并不会去执行最后的rejected 状态

三、PromiseResult

  1. let p1 = new Promise((resolve,reject)=>{
  2. resolve(1)
  3. })
  4. console.log(p1);

 通过resolve和rejected传入参数时通过打印就会发现PromiseResult的值(值可以是任意数据类型),怎么拿到PromiseResult的值呢

  1. new Promise((resolve,reject)=>{
  2. resolve('123')
  3. }).then(res=>console.log(res+'成功就会执行'))
  4. .catch(err=>{console.log(err+'失败就会执行')})
  5. .finally(()=>{console.log('不管成功还是失败都会执行');})

在then和catch方法中它的参数是一个回调函数,在这个回调函数中的参数中就可以拿到resolve传过来的值,也就是promiseValue,

当调用resolve函数时传过去的参数就会到.then中的回调函数的参数中    状态pending===》fulfilled

当调用reject函数时传过去的参数就会到.catch 中的回调函数的参数中     状态pending===》rejected

当然 你也可以省略定义p1的写法 

  1. new Promise((resolve,reject)=>{
  2. resolve('123')
  3. }).then(res=>console.log(res+'成功就会执行'))
  4. .catch(err=>{console.log(err+'失败就会执行')})
  5. .finally(()=>{console.log('不管成功还是失败都会执行');})

 .then中也可以写两个参数   第二个参数是可选的

当状态是pending===》fulfilled状态时会到.then中的第一个参数中的函数  pending===》rejected  回到.then中的第二个参数中的函数

  1. new Promise((resolve,reject)=>{
  2. reject(123)
  3. }).then((res)=>{ console.log(res+'成功') },
  4. (err)=>{ console.log(err+'失败') })

当你不去接收处理的 rejected状态时  会报出Uncaught (in promise)   中文意为未兑现(承诺)

  1. new Promise((resolve,reject)=>{
  2. reject(123)
  3. }).then((res)=>{ console.log(res+'成功') })

 四、promise链式调用

 在了解链式调用之前 先知道在这个.then函数中返回的是仍一个新的promise对象

  1. let p1 = new Promise((resolve,reject)=>{
  2. resolve('123')
  3. })
  4. let p2 = p1.then(res=>{})
  5. console.log(p2);
  6. console.log(p1===p2); //false

p2中的PromiseResult 拿到的返回值是p1.then 函数中的返回值而p1.then函数中 没有返回值  那么返回值就是undefined

p2的PromiseResult    =    p1.then的返回值  

为什么p2拿到的状态是fulfilled呢?不是rejected

1. 当.then中返回的不是promise对象时(包括undefined),p2的状态 一直都是fulfilled 

2.只有当.then中的 返回的是promsie对象 并且调用的状态是reject()就会失败 rejected 

例如下面这个例子就会返回 rejected 

  1. let p2 = p1.then(()=>{
  2. let p = new Promise((resolve,reject)=>{
  3. reject()
  4. })
  5. return p
  6. })
  7. console.log(p2);

当 .then函数中出现错误时 p2拿到的PromiseState的值是rejected,PromiseValue拿到的值是.then中出现的错误

  1. let p1 = new Promise((resolve, reject) => {
  2. resolve()
  3. });
  4. let p2 = p1.then(()=> {
  5. console.log(a); // 这里故意犯错
  6. });
  7. console.log(p2);

 

既然 p2 也是一个promise对象 我们就可以继续使用.then, 接下来 链式调用就开始了

  1. let p1 = new Promise((resolve, rejected) => {
  2. resolve(1)
  3. })
  4. let p2 = p1.then((res) => {
  5. console.log(res); //1
  6. return 2
  7. })
  8. p2.then((res)=>{
  9. console.log(res); //2
  10. })

 你当然页可以省略定义变量名  一直.then .then ~~的写

  1. new Promise((resolve, rejected) => {
  2. resolve(1)
  3. }).then((res) => {
  4. console.log(res);
  5. return 2
  6. }).then((res) => {
  7. console.log(res);
  8. })

五、回调地狱

模拟ajax 回调地狱 每次调用setTimeout 都是拿到上一次的值-1

  1. function fn1(a) {
  2. setTimeout(() => {
  3. console.log(a);
  4. a--;
  5. setTimeout(() => {
  6. console.log(a);
  7. a--
  8. setTimeout(() => {
  9. console.log(a);
  10. a--
  11. setTimeout(() => {
  12. console.log(a);
  13. a--
  14. setTimeout(() => {
  15. console.log(a);
  16. }, 1000);
  17. }, 1000);
  18. }, 1000);
  19. }, 1000);
  20. }, 1000);
  21. }
  22. fn1(5)

 看到上面的代码 像不像地狱级别的嵌套 如果每次ajax 都要拿上一次的值去发ajax 造成了很不好的维护性,读代码也很困难,如果解决呢,这就用到了promise

错误写法

 promise为什么能解决回调地狱  例如下面这个例子并没有去解决回调地狱  仍然造成了回调地狱 

  1. function fn1(a) {
  2. new Promise((res, rej) => {
  3. res(a)
  4. })
  5. .then((params) => {
  6. return new Promise((res, rej) => {
  7. setTimeout(() => {
  8. console.log(params);
  9. res(--params)
  10. return new Promise((res, rej) => {
  11. setTimeout(() => {
  12. console.log(params); res(--params)
  13. return new Promise((res, rej) => {
  14. setTimeout(() => {
  15. console.log(params); res(--params)
  16. return new Promise((res, rej) => {
  17. setTimeout(() => {
  18. console.log(params); res(--params)
  19. return new Promise((res, rej) => {
  20. setTimeout(() => {
  21. console.log(params); res(--params)
  22. }, 1000)
  23. })
  24. }, 1000)
  25. })
  26. }, 1000)
  27. })
  28. }, 1000)
  29. })
  30. }, 1000)
  31. })
  32. })
  33. }
  34. let a = 5
  35. fn1(a)

注意 优化成promise并不是在一个 .then里面 继续做操作   包括你在.then里继续new一个promise  并且一直嵌套这.then.then 还是会产生回调地狱,

正确写法

优化成 promise 发现就不会出现嵌套关系,而且不管写多少个 也是条条有序

  1. function fn1(a) {
  2. new Promise((res,rej)=>{
  3. res(a)
  4. })
  5. .then((params)=>{
  6. return new Promise((res,rej)=>{
  7. setTimeout(() => { console.log(params);res(--params) }, 1000) })
  8. })
  9. .then((params)=>{
  10. return new Promise((res,rej)=>{
  11. setTimeout(() => { console.log(params);res(--params) }, 1000) })
  12. })
  13. .then((params)=>{
  14. return new Promise((res,rej)=>{
  15. setTimeout(() => { console.log(params);res(--params) }, 1000) })
  16. })
  17. .then((params)=>{
  18. return new Promise((res,rej)=>{
  19. setTimeout(() => { console.log(params);res(--params) }, 1000) })
  20. })
  21. .then((params)=>{
  22. return new Promise((res,rej)=>{
  23. setTimeout(() => { console.log(params);res(--params) }, 1000) })
  24. })
  25. }
  26. let a=5
  27. fn1(a)

实例中优化

在下面中的demo中 在一个.then中又嵌套了两次.then  这就造成了回调地狱 ,你不需要关系内容 只需要知道如何解决

  1. return new Promise((resolve, reject) => {
  2. if (ctx.rootState.user.profile.token) {
  3. // 没有修改登录后的sku接口
  4. const oldGoods = ctx.state.list.find(it => it.skuId === oldSkuId)
  5. console.log(newSku)
  6. // 删除 拿到之前的skuId删除
  7. deleteCart([oldSkuId]).then(() => {
  8. // 添加最新的sku进入购物车
  9. return insertCart({ skuId: newSku.value.skuId, count: oldGoods.count }).then(() => {
  10. // 请求最新的数据
  11. return findCartList().then((data) => {
  12. ctx.commit('setCartList', data.result)
  13. resolve()
  14. })
  15. })
  16. })

优化 

  1. return new Promise((resolve, reject) => {
  2. if (ctx.rootState.user.profile.token) {
  3. // 没有修改登录后的sku接口
  4. const oldGoods = ctx.state.list.find(it => it.skuId === oldSkuId)
  5. console.log(newSku)
  6. // 删除 拿到之前的skuId删除
  7. deleteCart([oldSkuId])
  8. .then(() => { // 添加最新的sku进入购物车
  9. insertCart({ skuId: newSku.value.skuId, count: oldGoods.count })
  10. console.log(1)
  11. })
  12. .then(() => { findCartList(); })
  13. .then((data) => {
  14. ctx.commit('setCartList', data.result)
  15. resolve()
  16. })

再次优化 省略箭头函数中的大括号

  1. return new Promise((resolve, reject) => {
  2. if (ctx.rootState.user.profile.token) {
  3. // 没有修改登录后的sku接口
  4. const oldGoods = ctx.state.list.find(it => it.skuId === oldSkuId)
  5. console.log(newSku)
  6. // 删除 拿到之前的skuId删除
  7. deleteCart([oldSkuId])
  8. // 添加最新的sku进入购物车
  9. .then(() => insertCart({ skuId: newSku.value.skuId, count: oldGoods.count }))
  10. .then(() => { findCartList(); console.log(2) })
  11. .then((data) => {
  12. ctx.commit('setCartList', data.result)
  13. resolve()
  14. })
  15. }
  16. })

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/258991
推荐阅读
相关标签
  

闽ICP备14008679号