手写一个符合promiseA+规范的promise
872 passing (16s)
const PENDING = 'pending'const FULLFILLED = 'fullfilled'const REJECTED = 'rejected'class PromiseOfMine {constructor(executor) {// 捕获执行器的异常try {executor(this.resolve, this.reject)} catch (e) {this.reject(e)}}// promise的状态status = PENDING// 成功的值value = undefined// 失败的原因reason = undefined// 异步回调队列,用来放同一个promise多次then调用:p1.then(...); p1.then(...); p1.then(...);successCallback = []failCallback = []// 改变状态,执行异步回调resolve = (value) => {if (this.status !== PENDING) returnthis.status = FULLFILLEDthis.value = valuewhile (this.successCallback.length) {this.successCallback.shift()()}}reject = (reason) => {if (this.status !== PENDING) returnthis.status = REJECTEDthis.reason = reasonwhile (this.failCallback.length) {this.failCallback.shift()()}}// 判断状态,执行同步回调,如果是pending,就把异步回调存放起来,等到状态变更时触发then = (successCallback, failCallback) => {// 处理then没有参数的情况,把传过来的promise结果直接向后传递successCallback = typeof successCallback == 'function' ? successCallback : value => valuefailCallback = typeof failCallback == 'function' ? failCallback : reason => { throw reason }// 返回一个新的promise实现then的链式调用let newPromise = new PromiseOfMine((resolve, reject) => {// 执行同步回调if (this.status === FULLFILLED) {// setTimeout是为了保证resolvePromise变量已被声明setTimeout(() => {try {let x = successCallback(this.value)// 回调的结果x可能是一个普通值(没有返回值时是undefined),也可能是个promise,// 如果x是个普通值或者undefined,就直接resolve(x)传入新promise的then方法的成功回调// 如果x是个promise,就执行这个promise,判断这个promise的状态,根据状态调用resolve和rejectresolvePromise(newPromise, x, resolve, reject)} catch (e) {reject(e)}}, 0)} else if (this.status === REJECTED) {setTimeout(() => {try {let x = failCallback(this.reason)resolvePromise(newPromise, x, resolve, reject)} catch (e) {reject(e)}}, 0)}// 把异步回调放到异步回调数组中,状态改变后会立刻处理else {this.successCallback.push(() => {setTimeout(() => {try {let x = successCallback(this.value)resolvePromise(newPromise, x, resolve, reject)} catch (e) {reject(e)}}, 0)})this.failCallback.push(() => {setTimeout(() => {try {let x = failCallback(this.reason)resolvePromise(newPromise, x, resolve, reject)} catch (e) {reject(e)}}, 0)})}})return newPromise}finally = (callback) => {return this.then(value => {// callback可能是个promise对象,需要等到他执行完在returnreturn PromiseOfMine.resolve(callback()).then(() => value)}, reason => {return PromiseOfMine.reject(callback()).then(() => { throw reason })})}catch = (failCallback) => {return this.then(undefined, failCallback)}static all = (array) => {let result = []let process = 0return new PromiseOfMine((resolve, reject) => {function addData(index, value) {result[index] = valueprocess++if (process === array.length) {resolve(result)}}for (let i = 0; i < array.length; i++) {if (array[i] instanceof PromiseOfMine) {array[i].then(value => { addData(i, value) }, reason => reject(reason))} else {addData(i, array[i])}}})}static race = (array) => {return new PromiseOfMine((resolve, reject) => {for (let i = 0; i < array.length; i++) {array[i].then(data => {resolve(data)}, err => {reject(err)})}})}static resolve = (value) => {if (value instanceof PromiseOfMine) {return value} else {return new PromiseOfMine(resolve => resolve(value))}}static reject = (reason) => {if (reason instanceof PromiseOfMine) {return reason} else {return new PromiseOfMine((undefined, reject) => reject(reason))}}}function resolvePromise(newPromise, x, resolve, reject) {// x就是newPromiseif (newPromise === x) {return reject(new TypeError('error:promise循环调用'))}// x是一个函数或对象的情况,x就有可能是一个promiselet called// 保证只能调用成功或者失败,不能让用户两个都调用if (x != null && (typeof x === 'function' || typeof x === 'object')) {try {let then = x.then;if (typeof then === 'function') {then.call(x, (value) => {if (called) {return} else {called = true}// value可能还是一个promise,所以递归处理, 直到最终返回一个普通值为止resolvePromise(newPromise, value, resolve, reject)}, (reason) => {if (called) {return} else {called = true}reject(reason)})} else {// x.then是普通值{then:123}resolve(x)}} catch (e) {if (called) {return} else {called = true}reject(e)}}// x是一个普通值else {resolve(x)}}PromiseOfMine.deferred = function () {let dfd = {};dfd.promise = new PromiseOfMine((resolve, reject) => {dfd.resolve = resolve;dfd.reject = reject;});return dfd;}module.exports = PromiseOfMine;
