美文网首页
⼿写 Promise

⼿写 Promise

作者: ZoranLee | 来源:发表于2020-09-14 11:51 被阅读0次

实现Promise

const PENDING = 'pending' 
const RESOLVED = 'resolved'
 const REJECTED = 'rejected'
function MyPromise(fn) {
const that = this
that.state = PENDING
that.value = null
that.resolvedCallbacks = []
that.rejectedCallbacks = []
}
  • 一个 Promise 的当前状态必须为以下三种状态中的一种:
    等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)
  • ⼀开始 Promise 的状态应该是 pending
  • value 变量⽤于保存 resolve 或者 reject 中传⼊的值
  • resolvedCallbacks 和 rejectedCallbacks ⽤于保存 then 中的回调,因为当执⾏完 Promise 时状态可能还是等待 中,这时候应该把 then 中的回调保存起来⽤于状态改变时使 ⽤

resolve、reject

function resolve(value) {
     if (that.state === PENDING) {
         that.state = RESOLVED 
         that.value = value 
         that.resolvedCallbacks.map(cb => cb(that.value)) 
    }
 }

function reject(value) { 
if (that.state === PENDING) {
     that.state = REJECTED 
     that.value = value 
     that.rejectedCallbacks.map(cb => cb(that.value)) 
} 
}
  • ⾸先两个函数都得判断当前状态是否为等待中,因为规范规定 只有等待态才可以改变状态
  • 将当前状态更改为对应状态,并且将传⼊的值赋值给 value
  • 遍历回调数组并执⾏

Promise

try { 
fn(resolve, reject)
 } catch (e) {
 reject(e) 
}

then 函数

MyPromise.prototype.then = function(onFulfilled, onRejected) { 
const that = this 
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v onRejected = typeof onRejected === 'function' ? onRejected : r => {
 throw r 
} 
if (that.state === PENDING) { 
that.resolvedCallbacks.push(onFulfilled) that.rejectedCallbacks.push(onRejected)
 }
if (that.state === RESOLVED) {
 onFulfilled(that.value) 
}
if (that.state === REJECTED) { 
onRejected(that.value)
 } 
}
  • ⾸先判断两个参数是否为函数类型,因为这两个参数是可选参数
  • 当参数不是函数类型时,需要创建⼀个函数赋值给对应的参 数,同时也实现了透传,⽐如如下代码
Promise.resolve(4).then().then((value) => console.log(value))
  • 接下来就是⼀系列判断状态的逻辑,当状态不是等待态时,就 去执⾏相对应的函数。如果状态是等待态的话,就往回调函数 中 push 函数,⽐如如下代码就会进⼊等待态的逻辑
new MyPromise((resolve, reject) => {
 setTimeout(() => {
 resolve(1) }, 0) 
}).then(value => { 
console.log(value) 
})

优化

resolve、reject

function resolve(value) {
 if (value instanceof MyPromise) { 
return value.then(resolve, reject) 
}
setTimeout(() => {
 if (that.state === PENDING) 
{ that.state = RESOLVED
 that.value = value 
that.resolvedCallbacks.map(cb => cb(that.value)) } }, 0) 
}
function reject(value) { 
setTimeout(() => {
 if (that.state === PENDING) {
 that.state = REJECTED 
 that.value = value that.rejectedCallbacks.map(cb => cb(that.value)) } }, 0)
 }
  • 对于 resolve 函数来说,⾸先需要判断传⼊的值是否为 Promise 类型
  • 为了保证函数执⾏顺序,需要将两个函数体代码使⽤ setTimeout 包裹起来

then 函数

  • 新增⼀个变量 promise2,因为每个 then 函数都需要返回⼀个新的 Promise 对 象,该变量⽤于保存新的返回对象,然后我们先来改造判断等待态的逻辑
if (that.state === PENDING) { 
return (promise2 = new MyPromise((resolve, reject) => { that.resolvedCallbacks.push(() => { 
try { 
const x = onFulfilled(that.value) 
resolutionProcedure(promise2, x, resolve, reject)} catch (r) { 
reject(r)
 } })
that.rejectedCallbacks.push(() => { 
try { 
const x = onRejected(that.value) 
resolutionProcedure(promise2, x, resolve, reject)
} catch (r) {
 reject(r) 
} 
})
 })) }
  • ⾸先我们返回了⼀个新的 Promise 对象,并在 Promise 中 传⼊了⼀个函数
  • 函数的基本逻辑还是和之前⼀样,往回调数组中 push 函数
  • 同样,在执⾏函数的过程中可能会遇到错误,所以使⽤了 try...catch 包裹
  • 规范规定,执⾏ onFulfilled 或者 onRejected 函数时会 返回⼀个 x,并且执⾏ Promise 解决过程,这是为了不同的 Promise 都可以兼容使⽤,⽐如 JQuery 的 Promise 能兼容ES6 的 Promise

判断执⾏态的逻辑

if (that.state === RESOLVED) {
 return (promise2 = new MyPromise((resolve, reject) => {
 setTimeout(() => {
 try { 
const x = onFulfilled(that.value) 
resolutionProcedure(promise2, x, resolve, reject)
} catch (reason) { 
reject(reason) }
 }) })) 
}

兼容多种 Promise 的 resolutionProcedure 函数

function resolutionProcedure(promise2, x, resolve, reject) {
 if (promise2 === x) { 
return reject(new TypeError('Error')) 
} 
}
let called = false 
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
 try { 
let then = x.then 
if (typeof then === 'function') { 
then.call( x,y => { 
if (called) return called = true 
resolutionProcedure(promise2, y, resolve, reject)
 },e => {
 if (called) return called = true 
reject(e) } ) 
} else { 
resolve(x) }
 } catch (e) { 
if (called) return called = true 
reject(e) } } 
else { 
resolve(x) 
}
  • 创建⼀个变量 called ⽤于判断是否已经调⽤过函数
  • 然后判断 x 是否为对象或者函数,如果都不是的话,将 x 传⼊ resolve 中
  • 如果 x 是对象或者函数的话,先把 x.then 赋值给 then,然 后判断 then 的类型,如果不是函数类型的话,就将 x 传⼊ resolve 中
  • 如果 then 是函数类型的话,就将 x 作为函数的作⽤域 this 调⽤之,并且传递两个回调函数作为参数,第⼀个参数叫做 resolvePromise ,第⼆个参数叫做 rejectPromise,两 个回调函数都需要判断是否已经执⾏过函数,然后进⾏相应的 逻辑
  • 以上代码在执⾏的过程中如果抛错了,将错误传⼊ reject 函 数中

相关文章

  • ⼿写 Promise

    Promises/A+规范 https://www.ituring.com.cn/article/66566 实现...

  • promise

    上面这段代码换成promise怎么写? 创建promise对象方法

  • promise写delay

    用promise写一个delay function delay(ms){ return new Promise(r...

  • es6之深入理解Promise

    一、promise入门 1. Promise对象是什么 2.以前回调这么写 3.用Promise 写回调 4.多层...

  • Promise基本概念

    Promise用的很多,比较熟悉Promise的使用,一直没有思考过Promise的实现,今天尝试着写一个完整的P...

  • Promise??What?

    本来想直接写ES7的async-await的,后来一想这不就是Promise的语法糖吗,算了,还是写Promise...

  • [稀土掘金日报] 前端中的各种奇技淫巧

    超详细介绍promise的gitbook,看完再不会promise......web 开发者可以把自己写的 web...

  • 关于promise的一些心得

    1.promise想要链式写,(等待上一步的执行结果的话),需要重新new promise 对象并return 出...

  • JavaScript异步编程

    首发于我的博客 jolyon.cc 从Promise开始 Promise起源 推荐看这个日本人写的《JavaScr...

  • ES6 Promise 异步1

    - 异步 和 同步 promise对象: 用同步方式书写异步代码 promise 让异步写起来,像写同步一样流程...

网友评论

      本文标题:⼿写 Promise

      本文链接:https://www.haomeiwen.com/subject/wxtzektx.html