关于javascript:从零开始实现一个Promise

52次阅读

共计 6908 个字符,预计需要花费 18 分钟才能阅读完成。

1.Promise 产生背景及标准

家喻户晓,Promise 是 ES6 引入的新个性,旨在解决回调天堂。上面是一个简略的例子:管制接口调用程序:

apiA–>apiB–>apiC。简单的业务,开发人员会裂开。后生在此向老前辈致敬。

// 回调天堂
apiA({handleSuccess(resA){
        apiB({handleSuccess(resB){
                apiC({handleSuccess(resC){}})
            }
        })
    }
})

因而 Promise/A+ 标准应运而生,ES6 的 Promise 就是遵循标准开发进去的。

2. 同步 Promise

浏览标准可得上面几点根本要求:

  1. Promise 存在三个状态:pending(期待态)、fulfilled(胜利态)、rejected(失败态)
  2. pending 为初始态,并能够转化为 fulfilled 和 rejected
  3. 胜利时,不可转为其余状态,且必须有一个不可扭转的值(value)
  4. 失败时,不可转为其余状态,且必须有一个不可扭转的起因(reason)
  5. new Promise(executor=(resolve,reject)=>{resolve(value)}),resolve(value) 将状态置为 fulfilled
  6. new Promise(executor=(resolve,reject)=>{reject(reson)}),reject(reson) 将状态置为 rejected
  7. 若是 executor 运行异样执行 reject()
  8. thenable:then(onFulfilled, onRejected)

    1. onFulfilled:status 为 fulfilled,执行 onFulfilled,传入 value
    2. onRejected:status 为 rejected,执行 onRejected,传入 reason
// 1.Promise 存在三个状态:pending(期待态)、fulfilled(胜利态)、rejected(失败态)const STATUS_PENDING = 'pending'
const STATUS_FULFILLED = 'fulfilled'
const STATUS_REJECTED = 'rejected'
class myPromise {constructor(executor) {
      // pending 为初始态,并能够转化为 fulfilled 和 rejected
    this.status = STATUS_PENDING
    this.value = '' // 3
    this.reason = '' // 4

    let resolve = value => {
    // 5.
      if (this.status === STATUS_PENDING) {
        this.status = STATUS_FULFILLED
        this.value = value
      }
    }
    let reject = reason => {
    //6.
      if (this.status === STATUS_PENDING) {
        this.status = STATUS_REJECTED
        this.reason = reason
      }
    }
    // 7.
    try {executor(resolve, reject);
    } catch (err) {reject(err);
    }
  }
  // 8.
  then(onFulfilled = () => {}, onRejected = () => {}) {
      // 8.1
    if (this.status === STATUS_FULFILLED) {onFulfilled(this.value)
    }
    // 8.2
    if (this.status === STATUS_REJECTED) {onRejected(this.reason)
    }
  }
}
new myPromise(resolve => {console.log('before resolve')
  resolve(1)
}).then(res => {console.log(res)
})

new myPromise((resolve, reject) => {console.log('before reject')
  reject('reject error')
}).then(res => {console.log(res)
}, error => {console.log(error)
})

参考 前端手写面试题具体解答

3. 异步 Promise

new myPromise(resolve => {console.log('before resolve')
  setTimeout(()=>{resolve(1)
  },1000)
}).then(res => {console.log(res)
})

promise 的状态只能在 resolve 或者 reject 的时候扭转,同步代码执行到 then 回调的时候 promise 的状态还是 pending,明细不合乎咱们的冀望。

如果换做是你,你会怎么解决这个问题?举个栗子,你正在解决一堆事件(pending 状态),而后(then),老板曰: 一秒内做完手上的事来一下我办公室,做不完滚蛋。你怕遗记,个别会用清单记录 onResolvedCallbacks = [‘ 做完了手上的事, 去老板办公室 ’],onRejectedCallbacks = [‘ 做不完, 滚蛋 ’],1 秒后看实现后果,再根据抉择下一步。

欠缺后的代码如下:

const STATUS_PENDING = 'pending'
const STATUS_FULFILLED = 'fulfilled'
const STATUS_REJECTED = 'rejected'
class myPromise {constructor(executor) {
    this.status = STATUS_PENDING
    this.value = ''this.reason =''

    // 胜利寄存的数组
    this.onResolvedCallbacks = [];
    // 失败寄存法数组
    this.onRejectedCallbacks = [];

    let resolve = value => {if (this.status === STATUS_PENDING) {
        this.status = STATUS_FULFILLED
        this.value = value
        // pending->fulfilled 依照胜利清单执行
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }
    let reject = reason => {if (this.status === STATUS_PENDING) {
        this.status = STATUS_REJECTED
        this.reason = reason
        // pending->rejected 依照异样清单执行
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    }
    try {executor(resolve, reject);
    } catch (err) {reject(err);
    }
  }
  then(onFulfilled = () => {}, onRejected = () => {}) {if (this.status === STATUS_FULFILLED) {onFulfilled(this.value)
    }
    if (this.status === STATUS_REJECTED) {onRejected(this.reason)
    }
    // 繁忙状态, 先记录老板嘱咐的内容
    if (this.status === STATUS_PENDING) {
      // onFulfilled 传入到胜利数组
      this.onResolvedCallbacks.push(() => onFulfilled(this.value))
      // onRejected 传入到失败数组
      this.onRejectedCallbacks.push(() => onRejected(this.reason))
    }
  }
}
// 异步
new myPromise((resolve, reject) => {console.log('老板曰: 一秒做完手上的事来一下我办公室, 做不完滚蛋')
  setTimeout(() => {if (false) { // 臣妾做不到啊
      resolve('做完了手上的事, 去老板办公室')
    } else {reject('做不完, 滚蛋')
    }
  }, 1000)
}).then(res => {console.log(`1s 后:${res}`)
}, error => {console.log(`1s 后:${error}`)
})
// 老板曰: 一秒做完手上的事来一下我办公室, 做不完滚蛋
// 1s 后: 做不完, 滚蛋 

4. new Promise().then().then()…

这个思路倒是挺简略,就是 then 函数返回值为另一个 Promise 实例。依据标准批改后如下:

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function resolvePromise(promise2, x, resolve, reject) {
  // 循环援用报错
  if (x === promise2) {
    // reject 报错
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  // 避免屡次调用
  let called;
  // x 不是 null 且 x 是对象或者函数
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      // A+ 规定,申明 then = x 的 then 办法
      let then = x.then;
      // 如果 then 是函数,就默认是 promise 了
      if (typeof then === 'function') {
        // 就让 then 执行 第一个参数是 this   前面是胜利的回调 和 失败的回调
        then.call(x, y => {
          // 胜利和失败只能调用一个
          if (called) return;
          called = true;
          // resolve 的后果仍旧是 promise 那就持续解析
          resolvePromise(promise2, y, resolve, reject);
        }, err => {
          // 胜利和失败只能调用一个
          if (called) return;
          called = true;
          reject(err); // 失败了就失败了
        })
      } else {resolve(x); // 间接胜利即可
      }
    } catch (e) {
      // 也属于失败
      if (called) return;
      called = true;
      // 取 then 出错了那就不要在继续执行了
      reject(e);
    }
  } else {resolve(x);
  }
}

class Promise {constructor(executor) {
    this.state = PENDING
    this.value = ''this.reason =''

    // 胜利寄存的数组
    this.onResolvedCallbacks = [];
    // 失败寄存法数组
    this.onRejectedCallbacks = [];

    let resolve = value => {if (this.state === PENDING) {
        this.state = FULFILLED
        this.value = value
        // pending->fulfilled 依照胜利清单执行
        this.onResolvedCallbacks.forEach(fn => fn())
      }
    }
    let reject = reason => {if (this.state === PENDING) {
        this.state = REJECTED
        this.reason = reason
        // pending->rejected 依照异样清单执行
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    }
    try {executor(resolve, reject);
    } catch (err) {reject(err);
    }
  }
  then(onFulfilled, onRejected) {
    // onFulfilled 如果不是函数,就疏忽 onFulfilled,间接返回 value
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    // onRejected 如果不是函数,就疏忽 onRejected,扔出谬误
    onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err};
    let promise2 = new Promise((resolve, reject) => {if (this.state === FULFILLED) {
        // 异步解决:// onRejected 返回一个一般的值,失败时如果间接等于 value => value,// 则会跑到下一个 then 中的 onFulfilled 中,setTimeout(() => {
          try {let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {reject(e);
          }
        }, 0);
      };
      if (this.state === REJECTED) {setTimeout(() => {
          try {let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {reject(e);
          }
        }, 0);
      };
      if (this.state === PENDING) {this.onResolvedCallbacks.push(() => {setTimeout(() => {
            try {let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {reject(e);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push(() => {setTimeout(() => {
            try {let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {reject(e);
            }
          }, 0)
        });
      };
    });
    return promise2;
  }
}
new Promise(resolve => {console.log(0)
    setTimeout(() => resolve(1), 3000)
  })
  .then(res => {console.log(res)
    return new Promise(resolve => {console.log(2)
      setTimeout(() => {resolve(3)
      }, 3000)
    })
  })
  .then(res => {console.log(res)
  })

5. catch、resolve、reject、race 和 all

1. catch(非凡的 then 办法)

catch(fn){return this.then(null,fn)
}

2. resolve(resolve 一个值)

Promise.resolve = val => new Promise(resolve=> resolve(val))

3. reject(reject 一个值)

Promise.reject = val => new Promise((resolve,reject)=> reject(val))

4. race

Promise.race([p1, p2, p3]) 外面哪个后果取得的快,就返回那个后果,不论后果自身是胜利状态还是失败状态。

Promise.race = promises =>
  new Promise((resolve, reject) =>
    promises.forEach(pro => pro.then(resolve, reject))
  )

5. all

Promise.all 能够将多个 Promise 实例包装成一个新的 Promise 实例。同时,胜利和失败的返回值是不同的,胜利的时候返回的是一个后果数组,而失败的时候则返回最先被 reject 失败状态的值。

Promise.all = function (promises) {return new Promise((resolve, reject) => {
    let index = 0;
    let result = [];
    if (promises.length === 0) {resolve(result);
    } else {function processValue(i, data) {result[i] = data;
        if (++index === promises.length) {resolve(result);
        }
      }
      for (let i = 0; i < promises.length; i++) {//promises[i] 可能是一般值
        Promise.resolve(promises[i]).then((data) => {processValue(i, data);
        }, (err) => {reject(err);
          return;
        });
      }
    }
  });
}

本文旨在记录学习过程,通过手打代码加深印象

正文完
 0