IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 三分钟带你手写一个完整的Promise -> 正文阅读

[JavaScript知识库]三分钟带你手写一个完整的Promise

三分钟带你手写一个完整的Promise

实现一个基础

Promise 是类,接受一个函数参数,然后内部有status 变量和then方法,status状态初始值为pending(等待),then方法的回调函数暂存于内存中,当参数函数的需要提前执行的异步操作执行完之后,执行成功会resolve(value),status变为fulfilled,statu执行失败则会有reject(err),status变为rejected

由以上分析,可以撸出代码:

class MyPromise {
  constructor(fn) {
    this.status = 'pending'
    this.value = null
    this.err = null
    this.fulfilledCallback = null
    this.rejectedCallback = null
    const resolve = value => {
      this.status = 'fulfilled'
      this.value = value
      this.fulfilledCallback(value)
    }
    const reject = err => {
      this.status = 'rejected'
      this.err = err
      this.rejectedCallback(err)
    }
    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then(success, fail) {
    this.fulfilledCallback = success
    this.rejectedCallback = fail
  }
}

实现了一个基础Promise的操作,可以进行new MyPromise 传入一个异步函数,然后.then的异步操作

new MyPromise((resolve, reject) => { 
  setTimeout(() => {
    console.log(12)
    resolve(34) 
  }) 
}).then(rsp => { 
  console.log(rsp) 
})
// 输出 12 34

但是再跟一个.then 就会报错

解决链式操作的报错

但是,这样实现只有一个then函数,真正的Promis后面可以跟很多个then函数,我们可以在此基础上重新写一下then 方法,将this对象返回出来

...
then(success, fail) {
  if (this.status === 'fulfilled') {
    success(this.value)
  }
  if (this.status === 'rejected') {
    fail(this.err)
  }
  this.fulfilledCallback = success
  this.rejectedCallback = fail
  return this
}

将成功事件函数和失败事件函数升级为队列

class MyPromise {
  constructor(fn) {
    this.status = 'pending'
    this.fulfilledCallbacks = []
    this.rejectedCallbacks = []
    const resolve = value => {
      this.fulfilledCallbacks.forEach(cb=>{
        cb(value)
      })
    }
    const reject = err => {
      this.rejectedCallbacks.forEach(cb=>{
        cb(err)
      })
    }
    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then(success, fail) {
    if (this.status === 'fulfilled') {
      this.value = success(this.value)
    } else if (this.status === 'rejected') {
      this.err = fail(this.err)
    } else {
      this.fulfilledCallbacks.push(success)
      this.rejectedCallbacks.push(fail)
    }
    return this
  }
}

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    console.log(12)
    resolve(34)
  })
}).then(rsp => {
  console.log(rsp)
}).then(rsp => {
  console.log(rsp)
})
// 12 34 34

这样下来,我们的所.then里面的回调函数都能够执行

实现下一个then里面的参数函数的实参是上一个的参数函数的返回值

Promise 除了能实现异步,还有完备的链式操作,还能够将上一个上一个then里面参数函数的返回值,作为then里面的参数函数的实参

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  })
}).then(rsp => {
  console.log(rsp)
  return 2
}).then(rsp => {
  console.log(rsp)
})
// 1 2

我们也动手实现一下,我的思路是,在resolve或者rejected之后,将这个forEach循环的函数返回值赋值给this.value,让我们试一下

...
const resolve = value => {
  this.value = value
  this.fulfilledCallbacks.forEach(cb=>{
    this.value = cb(this.value)
  })
}

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  })
}).then(rsp => {
  console.log(rsp)
  return 2
}).then(rsp => {
  console.log(rsp)
})
// 1 2

完成

实现Promise.all

话不多说直接上代码

static all(list) {
  const results =[]
  return new MyPromise((resolve, reject) => {
    list.forEach(promise => {
      promise.then(rsp => {
        results.push(rsp)
        if (results.length === list.length) {
          resolve(results)
        }
      })
    })
  })
}

由上可知,当队列中的promise执行一个就push进入结果队列,当最后一个resolve时候(resolve的最后一个不一定是队列的最后一个);结果也就全部push进去了,(results.length === list.length)来判断,最终返回的是 resolve结果的列表。

let p1 = new MyPromise((resolve)=> resolve(1))
let p2 = new MyPromise((resolve)=> {
  setTimeout(()=>{
    resolve(2)
  }, 1000)
})
let p3 = new MyPromise((resolve)=> {
  setTimeout(()=>{
    resolve(3)
  })
})

MyPromise.all([p1, p2, p3]).then(rsp=> {
  console.log(rsp)
})

// [1,3,2]

实现Promise.resolve

Promise.resolve 的实现就相对很简单了

...
static resolve(value) {
  return new MyPromise(resolve=>{
    resolve(value)
  })
}

经过测试也是没有问题的

MyPromise.resolve(1).then(rsp => {
  console.log(rsp)
})

// 1

整套代码

整个代码如下:

class MyPromise {
  constructor(fn) {
    this.status = 'pending'
    this.fulfilledCallbacks = []
    this.rejectedCallbacks = []
    const resolve = value => {
      this.status = 'fulfilled'
      this.value = value
      this.fulfilledCallbacks.forEach(cb=>{
        this.value = cb(this.value)
      })
    }
    const reject = err => {
      this.status = 'rejected'
      this.err = err
      this.rejectedCallbacks.forEach(cb=>{
        this.value = cb(this.err)
      })
    }
    try {
      fn(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then(success, fail) {
    if (this.status === 'fulfilled') {
      this.value = success(this.value)
    } else if (this.status === 'rejected') {
      this.err = fail(this.err)
    } else {
      this.fulfilledCallbacks.push(success)
      this.rejectedCallbacks.push(fail)
    }
    return this
  }
  static all(list) {
    const results =[]
    return new MyPromise((resolve, reject) => {
      list.forEach(promise => {
        promise.then(rsp => {
          results.push(rsp)
          if (results.length === list.length) {
            resolve(results)
          }
        })
      })
    })
  }
  static resolve(value) {
    return new MyPromise(resolve=>{
      resolve(value)
    })
  }
}

总结和讨论

我们也只是写了Promise相对用的多的一些功能,还有一个微任务的模拟没有实现,我们所知,resolve函数执行时候,是有个异步的,实现原理类似于node.js process.nextTick,这个涉及到底层的东西,我们这里就不做讨论

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 12:44:50  更:2021-10-27 12:45:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/12 0:31:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码