代码编织梦想

一、什么是promise

1. 本质

  • promise本质是一个对象,抽象理解为一个容器,里面放着一个异步的事件,会在未来执行,新建的promise处于pending状态,如果这个事件执行成功了状态就变为resolved,失败则为rejected。

2. 特点

  • 只能通过异步操作的结果确定promise的值
  • 状态转变不可逆

3. 创建promise

const promise = new Promise((resolve, reject) => {
  if (status) { // 异步操作成功
    resolve(1) // pending→resolved
  } else {
    reject(new Error('失败')) // pending→reject
  }
})
promise.then(result => console.log(result)).catch(error => console.log(error))

二、 promise方法

1. 实例方法

then、catch、finally

  • promise.then
    • promise实例状态改变时执行(执行resolve或reject)
    • 参数:(1)resolved状态执行函数(2)rejected状态执行函数
    • 返回一个新的promise
  • promise.catch
    • promise实例状态变为rejected时执行
    • 参数:rejected状态执行函数
    • promise.catch(rejection) = promise.then(null, rejection) = promise.then(undefined, rejection)
    • 返回一个新的promise
  • promise.finally
    • 无论promise状态是哪种,都会执行的方法
    • 参数:函数
    • 无返回值
    • 实现
    Promise.prototype.finally = function (callback) {
      let P = this.constructor;
      return this.then(
        value  => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
      );
    };
    

2. 静态方法

all、any、race、allSettled、race、resolve、reject

  • Promise.all
    • 将多个promise包装成一个新的promise
    • 当多个promise每一个fullfilled时新的promise状态会变为fullfilled,否则rejected
    • 参数:promise数组
    • 返回值:新的promise
    const p = Promise.all([p1, p2, p3]);
    // p1, p2, p3都fullfilled,p才fullfilled
    // p1, p2, p3任何一个rejected,p就rejected
    
  • Promise.any
    • 将多个promise包装成一个新的promise
    • 当多个promise任何一个fullfilled时新的promise状态会变为fullfilled,否则rejected
    • 参数:promise数组
    • 返回值:新的promise
  • Promise.race
    • 将多个promise包装成一个新的promise
    • 多个promise中的某一个状态改变,新的promise状态就追随改变
    const p = Promise.all([p1, p2, p3]);
    // p1, p2, p3任何一个发生状态改变,变成fullfilled,p就fullfilled,否则就rejected
    
  • Promise.allSettled
    • 将多个promise包装成一个新的promise
    • 多个promise中的每一个状态改变,新的promise状态变回fullfilled
    • 参数:promise数组
    • 返回值:参数数组返回的状态已经确定的promise数组,[{status: fullfilled/rejected, 成功value/失败reason}]
  • Promise.resolve
    • 把非promise转为promise对象
    • 参数
      • (1)promise实例:返回这个promise实例
      • (2)有then方法的对象:将这个对象转为promise对象,立即执行then方法,then方法执行后状态变为fullfilled
      • (3)没有then方法的对象或非对象:返回一个新的promise对象,状态为fullfilled
      • (4)不带参数:返回一个fullfilled状态的promise对象
      // 参数(1) promise实例
      const promise = new Promise((resolve, reject) => {
        resolve(1)
      })
      console.log(Promise.resolve(promise));
      // Promise {<fulfilled>: 1}
      //  [[Prototype]]: Promise
      //  [[PromiseState]]: "fulfilled"
      //  [[PromiseResult]]: 1
      
      // 参数(2) 有then方法的对象
      let thenable = {
        then: (resolve, reject) => {
          resolve('2-1')
        }
      }
      console.log(Promise.resolve(thenable)) // 为什么是pending?
      //  Promise {<pending>}
      //  [[Prototype]]: Promise
      //  [[PromiseState]]: "fulfilled"
      //  [[PromiseResult]]: 2-1
      
      // 参数(3) 没有then方法的对象或非对象
      // 情况1 没有then方法的对象
      let nothenable = {
        a: '3-1'
      }
      console.log(Promise.resolve(nothenable));
      // Promise {<fulfilled>: {…}}
      //  [[Prototype]]: Promise
      //  [[PromiseState]]: "fulfilled"
      //  [[PromiseResult]]: Object
      
      // 情况2 非对象
      console.log(Promise.resolve('3-2'));
      // Promise {<fulfilled>: '3-2'}
      //  [[Prototype]]: Promise
      //  [[PromiseState]]: "fulfilled"
      //  [[PromiseResult]]: "2-2"
      
      // 参数(4) 不带参数
      console.log(Promise.resolve());
      // Promise {<fulfilled>: undefined}
      //  [[Prototype]]: Promise
      //  [[PromiseState]]: "fulfilled"
      //  [[PromiseResult]]: undefined
      
  • Promise.reject
    • 返回一个rejected状态的promise

三、手写promise的主要方法

Promise实现

  • (1) 观察者模式

收集依赖 -> 触发通知 -> 取出依赖执行
Promise中的观察者模式:then()收集依赖 ->异步触发resolve -> resolve/reject执行回调

  • (2) new Promise的时候做了什么
    • Promise接收一个executor(执行器),在new Promise的时候立即执行executor回调
    • executor内部的异步操作被放入宏/微任务队列,等待执行
    • then被执行,收集成功/失败回调,放入成功/失败队列
    • executor内部的异步操作被执行,触发resolve/reject,从成功/失败队列中取出回调依次执行
  • (3) promise A+ 对状态的规定
    • 只有三种状态,pending、fullfilled、rejected
    • 状态只能从pending -> fullfilled 或者 pending -> rejected,且不可逆
  • (4) then方法如何链式调用
    • then方法返回了一个Promise
    • then方法需要拿到上一个then方法的返回值
    • then回调需要顺序执行
  • (5) then方法接收到非函数
    • 直接将值传递到成功函数中
  • (6) then方法中对状态的处理
    • 区分三种状态
      • pending时将成功函数和失败函数push进不同的队列
      • fullfilled时,执行成功函数,并且传入上一个then的返回值
      • rejected时,执行失败函数,并且传入上一个then的返回值
// Promise三种状态
const PENDING = 'pedding'
const FULLFILLED = 'fullfilled'
const REJECTED = 'rejected'

class MyPromise {
  constructor(executor) {
    this.resolveQueue = [] // 成功队列
    this.rejectQueue = [] // 失败队列
    this._status = PENDING // 初始化状态为pending
    this._value = undefined // 储存then的返回值

    let _resolve = (val) => {
      const run = () => {
        if (this._status !== PENDING) return // 如果状态已经改变,就直接return
        this._status = FULLFILLED // 变更状态
        this._value = val // 储存当前值
        while(this.resolveQueue.length) {
          const callback = this.resolveQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }

    let _reject = (val) => {
      const run = () => {
        if (this._status !== PENDING) return
        this._status = REJECTED
        this._value = val
        while(this.rejectQueue.length) {
          const callback = this.rejectQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }

    executor(_resolve, _reject)
  }

  // Promise.prototype.then
  then(resolveFn, rejectFn) {
    // 非函数情况处理
    typeof resolveFn !== 'function' ? resolveFn = value => value : null
    typeof rejectFn !== 'function' ? rejectFn = reason => {
      throw new Error(reason instanceof Error ? reason.message : reason)
    } : null
    // then方法返回一个新的promise,才能实现链式调用
    return new MyPromise((resolve, reject) => {
      const fullfilledFn = value => {
        try {
          // 获取执行第一个promise的成功回调及返回值
          let res = resolveFn(value)
          // 返回值如果还是一个promise,则可以继续调新的promise的then方法,否则直接resolve
          res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
        } catch(err) {
          reject(err)
        }
      }

      const rejectedFn = error => {
        try {
          let res = rejectFn(error)
          res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
        } catch(err) {
          reject(err)
        }
      }

      // resolve/reject状态处理
      switch(this._status) {
        case PENDING:
          this.resolveQueue.push(fullfilledFn)
          this.rejectQueue.push(rejectedFn)
          break;
        case FULLFILLED:
          fullfilledFn(this._value)
          break;
        case REJECTED:
          rejectedFn(this._value)
          break;
      }
    })
  }

  // Promise.prototype.catch
  catch(rejectFn) {
    return this.then(undefined, rejectFn)
  }

  // Promise.prototype.finally
  finally(callback) {
    return this.then(
      value => MyPromise.resolve(callback()).then(() => value)
      reason => MyPromise.reject(callback()).then(() => throw reason)
    )
  }
}

const p1 = new MyPromise((resolve, reject) => {
  resolve(1)          //同步executor测试
})

p1
  .then(res => {
    console.log(res)
    return 2          //链式调用测试
  })
  .then()             //值穿透测试
  .then(res => {
    console.log(res)
    return new MyPromise((resolve, reject) => {
      resolve(3)      //返回Promise测试
    })
  })
  .then(res => {
    console.log(res)
    throw new Error('reject测试')   //reject测试
  })
  .then(() => {}, err => {
    console.log(err)
  })

1. Promise.resolve

  • 只区分是Promise对象的情况,其他用new Promise包装,就可实现
static resolve(value) {
  if (value && typeof value === 'object' && value instanceof MyPromise) {
    return value
  }
  return new MyPromise((resolve) => {
    resolve(value)
  })
}

2. Promise.reject

static reject(reason) {
  return new MyPromise((resolve, reject) => reject(reason))
}

3. Promise.all

static all(promiseArr) {
  let index = 0
  let result = []
  return new MyPromise((resolve, reject) => {
    promiseArr.forEach((p, i) => {
      MyPromise.resolve(p).then(
        val => {
          index++
          result[i] = val
          if (index === promiseArr.length) resolve(result)
        },
        err => {
          reejct(err)
        }
      )
    })    
  })
}

4. Promise.race

static race(promiseArr) {
  return new MyPromise((resolve, reject) => {
    promiseArr.forEach(p => {
      MyPromise.resolve(p).then(
        value => resolve(value),
        err => reject(err)
      )
    })
  })
}

四、奇怪的面试题

1. question one

Promise.resolve().then(() => {
  console.log(0);
  return Promise.resolve(4);
}).then((res) => {
    console.log(res)
})

Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(5);
}).then(() =>{
    console.log(6);
})
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ffffff32/article/details/131023359

vue 获取url地址的参数-爱代码爱编程

  url是一个 URL地址,我们在使用 vue的时候,经常需要获取 url的参数,获取方法有很多种,这里我只介绍一种获取 url参数的方法,那就是使用 Requests. urlset. newContext ()方法。 这个方法就是调用 requests. urlset. newContext ()方法来获取 url的参数。在这个方法中,我们需要

vite的使用-爱代码爱编程

私人博客 许小墨のBlog —— 菜鸡博客直通车 系列文章完整版,配图更多,CSDN博文图片需要手动上传,因此文章配图较少,看不懂的可以去菜鸡博客参考一下配图! 系列文章目录 前端系列文章——传送

vue2-爱代码爱编程

目录 计算属性 计算属性缓存vs方法 计算属性vs侦听属性 getter和setter 计算属性和监听器 前端调用api实现问答 侦听器 计算属性 鉴于能在插值表达式中写js表达式;这样做也一定程度上违背了设计插值表达式的初衷;特别是:   其实就相当于不建议你在html标签里写css属性这一类规范;因为实

【华为od机试真题2023b卷 java&js】阿里巴巴找黄金宝箱(v)_一贫如洗的樵夫阿里巴巴,javascript-爱代码爱编程

华为OD2023(B卷)机试题库全覆盖,刷题指南点这里 阿里巴巴找黄金宝箱(V) 知识点数组哈希表滑窗  时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 一贫如洗的樵夫阿里巴巴在去砍柴的路上,无意中发现了强盗集团的藏宝地,藏宝地有编号从0~N的箱子,每个箱子上面贴有一个数字。 阿里巴巴念出一个咒语数

vue-爱代码爱编程

效果图  kindeditor 引入     一、去官网下载 kindeditor 包  官方链接            二、在vue里的static文件夹下 创建一个 文件夹名字叫 kindeditor, 把下载好的文件放在这里  三、在 公共组件 components 下 创建kindeditor.vue 文件 <

vue中组件的几个重要点_vue什么时候组件名要加单引号-爱代码爱编程

1 单词命名组件名称 vue推荐的命名组件名称有以下几种: 首先看下组件有几个单词构成 单个单词 如果只有一个单词,那么建议全部小写,用的时候也是全部小写的,或者首字母大写 有人喜欢哪怕只有一个单词也首字母大写

react antd modal里form设置值不起作用_antdpro modalform无效-爱代码爱编程

问题描述: react antd Modal里Form设置值不起作用,即使用form的api。比如:编辑时带出原有的值。 造成的原因:一般设置值都是在声明周期里设置,比如:componentDidMounted里设置,hook则在useEffetc里设置,因为Form在Modal里,会造成 form还没渲染完,就已经设置完值的情况 即在调用form的实

vue基础入门(下)_vux.:nv b& b bin-爱代码爱编程

<script src="https://unpkg.com/vue@next"></script> nvm安装node.jsnvm文档手册 - nvm是一个nodejs版本管理工具 - nvm中文网 (uihtm.com) mixin混入(局部使用) 定义mixin对象  <script> // mix