深入理解promise原理以及相关方法,并手写代码

2024-06-18 00:23:25

浏览:75

评论:0

JavaScript中的Promise是一种处理异步操作的编程模式,它提供了一种更加优雅的方式来组织和管理异步代码,避免了传统回调函数的回调地狱问题。

核心原理

Promise的核心原理基于状态机,其生命周期有三种状态:

  • Pending(等待中):初始状态,既不是fulfilled也不是rejected,代表Promise还在等待结果。
  • Fulfilled(已成功):当异步操作成功完成时,Promise的状态变为fulfilled,此时它可以传递一个成功的值。
  • Rejected(已失败):当异步操作失败或者出错时,Promise的状态变为rejected,此时它可以传递一个错误原因。

Promise一旦从Pending变为Fulfilled或Rejected,它的状态就不可更改了,这称为Promise的不可变性。

实现Promise

Promise的规范有很多,如Promise/A、Promise/B、Promise/D以及Promise/A的升级版Promise/A+,其中ES6遵循Promise/A+规范

逻辑代码

  • Promise接受一个函数,并可以链式调用then、catch、finally方法。
  • 扩展方法allSettled、all、race。
// 手写promise 加状态
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 完成
const REJECTED = 'rejected'; // 失败

function MyPromise(fn) {
  let self = this;
  self.value = null; // Promise成功的值
  self.error = null; // Promise失败的值
  self.status = PENDING; // 初始状态
  self.onFulfilledCallback = []; // Promise的 resolve回调
  self.onRejectedCallback = []; // Promise的 reject回调

  function resolve(value) {
    if (self.status === PENDING) {
      setTimeout(function () {
        self.status = FULFILLED;
        self.value = value;
        self.onFulfilledCallback.forEach(function (callback) {
          callback && callback(value);
        });
      }, 0);
    }
  }

  function reject(error) {
    if (self.status === PENDING) {
      setTimeout(function () {
        self.status = REJECTED;
        self.error = error;
        self.onRejectedCallback.forEach(function (callback) {
          callback && callback(error);
        });
      }, 0);
    }
  }

  // 异常处理
  try {
    fn(resolve, reject); // 执行callback并传入相应的参数
  } catch (e) {
    reject(e)
  }
}

function resolvePromise(bridgepromise, x, resolve, reject) {
  //2.3.1规范,避免循环引用
  if (bridgepromise === x) {
    return reject(new TypeError('Circular reference'));
  }
  let called = false;
  //这个判断分支其实已经可以删除,用下面那个分支代替,因为promise也是一个thenable对象
  if (x instanceof MyPromise) {
    if (x.status === PENDING) {
      x.then(y => {
        resolvePromise(bridgepromise, y, resolve, reject);
      }, error => {
        reject(error);
      });
    } else {
      x.then(resolve, reject);
    }
    // 2.3.3规范,如果 x 为对象或者函数
  } else if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) {
    try {
      // 是否是thenable对象(具有then方法的对象/函数)
      //2.3.3.1 将 then 赋为 x.then
      let then = x.then;
      if (typeof then === 'function') {
        //2.3.3.3 如果 then 是一个函数,以x为this调用then函数,且第一个参数是resolvePromise,第二个参数是rejectPromise
        then.call(x, y => {
          if (called) return;
          called = true;
          resolvePromise(bridgepromise, y, resolve, reject);
        }, error => {
          if (called) return;
          called = true;
          reject(error);
        })
      } else {
        //2.3.3.4 如果 then不是一个函数,则 以x为值fulfill promise。
        resolve(x);
      }
    } catch (e) {
      //2.3.3.2 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

// then的实现
MyPromise.prototype.then = function (onFulfilled, onRejected) {
  console.log(this, onFulfilled, onRejected);
  const self = this;
  console.log(self.status);
  let bridgePromise = null;
  // 设置默认函数
  onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
  onRejected = typeof onRejected === "function" ? onRejected : error => { throw error };

  if (self.status === FULFILLED) {
    return bridgePromise = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onFulfilled(self.value);
          resolvePromise(bridgePromise, x, resolve, reject);
        } catch (err) {
          reject(err)
        }
      })
    })
  } else if (self.status === REJECTED) {
    return bridgePromise = new MyPromise((resolve, reject) => {
      setTimeout(() => {
        try {
          let x = onRejected(self.error);
          resolvePromise(bridgePromise, x, resolve, reject);
        } catch (err) {
          reject(err)
        }
      })
    })
  } else {
    return bridgePromise = new MyPromise((resolve, reject) => {
      self.onFulfilledCallback.push((value) => {
        try {
          let x = onFulfilled(value);
          console.log(x)
          resolvePromise(bridgePromise, x, resolve, reject);
        } catch (err) {
          reject(err)
        }
      });
      self.onRejectedCallback.push((error) => {
        try {
          let x = onRejected(error);
          resolvePromise(bridgePromise, x, resolve, reject);
        } catch (err) {
          reject(err)
        }
      });
    })
  }
}

// catch 的实现
MyPromise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected)
}

// finally 的实现
MyPromise.prototype.finally = function (callback) {
  return this.then(function (value) {
    return MyPromise.resolve(callback()).then(function () {
      return value
    })
  }, function (err) {
    return MyPromise.resolve(callback()).then(function () {
      throw err
    })
  })
}

// race
MyPromise.race = function (values) {
  return new MyPromise(function (resolve, reject) {
    values.forEach(function (value) {
      MyPromise.resolve(value).then(resolve, reject)
    })
  })
}

// all
MyPromise.all = function (arr) {
  var args = Array.prototype.slice.call(arr)
  return new MyPromise(function (resolve, reject) {
    if (args.length === 0) return resolve([])
    var remaining = args.length
    for (var i = 0; i < args.length; i++) {
      res(i, args[i])
    }
    function res(i, val) {
      if (val && (typeof val === 'object' || typeof val === 'function')) {
        if (val instanceof MyPromise && val.then === MyPromise.prototype.then) {
          if (val.currentState === FULFILLED) return res(i, val.value)
          if (val.currentState === REJECTED) reject(val.value)
          val.then(function (val) {
            res(i, val)
          }, reject)
          return
        } else {
          var then = val.then
          if (typeof then === 'function') {
            var p = new MyPromise(then.bind(val))
            p.then(function (val) {
              res(i, val)
            }, reject)
            return
          }
        }
      }
      args[i] = val
      if (--remaining === 0) {
        resolve(args)
      }
    }
  })
}

// allSettled
MyPromise.allSettled = function (promises) {
  return new MyPromise((resolve, reject) => {
    promises = Array.isArray(promises) ? promises : []
    let len = promises.length
    const argslen = len
    // 如果传入的是一个空数组,那么就直接返回一个resolved的空数组promise对象
    if (len === 0) return resolve([])
    // 将传入的参数转化为数组,赋给args变量
    let args = Array.prototype.slice.call(promises)
    // 计算当前是否所有的 promise 执行完成,执行完毕则resolve
    const compute = () => {
      if (--len === 0) {
        resolve(args)
      }
    }
    function resolvePromise(index, value) {
      // 判断传入的是否是 promise 类型
      if (value instanceof MyPromise) {
        const then = value.then
        then.call(value, function (val) {
          args[index] = { status: 'fulfilled', value: val }
          compute()
        }, function (e) {
          args[index] = { status: 'rejected', reason: e }
          compute()
        })
      } else {
        args[index] = { status: 'fulfilled', value: value }
        compute()
      }
    }

    for (let i = 0; i < argslen; i++) {
      resolvePromise(i, args[i])
    }
  })
}

测试代码

const my = new MyPromise(function (resolve, reject) {
  const data = process.argv;
  if (data) {
    resolve('成功');
  } else {
    reject('失败');
  }
})

const my1 = function () {
  return "my1";
}

const my2 = function () {
  return new MyPromise(function (resolve, reject) {
    resolve('my2');
  })
}

const my3 = "my3";

my.then((res) => {
  return new MyPromise(function (resolve, reject) {
    resolve('my2');
  })
}).then(res => {
  return 3;
})