学习Promise && 简易实现Promise

Promise和异步

  • Promise异步解决方案,是其余异步方案的基石
  • 异步:如今和未来之间的时间间隙
  • Promises/A+规范

Promise核心方法和辅助方法

  • Promise.prototype.then ( 核心 )
  • Promise.prototype.catch ( 辅助 )
  • Promise.resolve ( 辅助 )
  • Promise.reject ( 辅助 )
  • Promise.all ( 辅助 )
  • Promise.race ( 辅助 )
  • 阮一峰(promise)

Promise

  1. promise 状态变动后不可逆
  2. 同一个实例能够被屡次 then
  3. .then方法是异步且能够被链式调用( 返回新的promise )
  4. .then方法中用户能够显示的返回 promise ,且能够多层嵌套。实例以下图

http://occeqxmsk.bkt.clouddn.com/status_-all.png

Promise中也许是最麻烦的部分1 ( 订阅发布 )

  1. new Promise 中使用了异步方法,那么当前状态就会一直处于 pending 状态,直到在异步的回调中触发 resolvereject
  2. 那么在构造函数 Promise 中,就须要把then里面的成功和失败函数,存储在私有数组中 this.onResolvedArythis.onRejectedAry
  3. then 方法为 pending 状态时,把第一个成功参数 onFulFilled 和第二个失败参数 onRejected,分别存储到私有变量 this.onResolvedArythis.onRejectedAry
  4. 当异步回调中的 resolverejcet 被触发时,分别遍历对应的数组 (onResolvdeAry, onRejectedAry) 并执行便可

Promise中也许是最麻烦的部分2 ( 递归 )

默认返回Promise和用户显示的返回Promisejavascript

  1. defaultReturnPromise.then 中默认返回新的 promise (链式调用)
  2. userReturnValue:用户能够显示的返回 promise 或其余参数
  3. 若是用户返回的是普通字符,则直接调用 defaultReturnPromiseresolve
  4. 若是用户返回的是一个 promise,则看用户返回的 promise 内部调用的 resolve 仍是 reject
  5. 若是调用的是 resolve ,则拿着 resolve 的参数直接执行 defaultReturnPromiseresolve
  6. 若是调用的是 reject,则拿着这个错误参数直接执行 defaultReturnPromisereject
  7. 若是 resolve 中执行的又是一个新的 promise ,则重复执行上述规则(2-6)

new Promise轮廓

class Promise {
  constructor(executor) {
    let resolve = success_value => {};
    let reject = fail_reason => {};
    executor(resolve, reject);
  }
  then(onFulFilled, onRejected) {}
}
复制代码

状态不可逆

Promise/A+ (2.1) promise状态: 必须处于如下三种状态中的一种 pending( 等待 )、fulfilled( 完成 )、rejected( 失败 )java

pending 能够转换成 fulfilledrejected,只要转换了完成或失败,则不可逆es6

class Promise {
  constructor(executor) {
    this.status = 'pending';// 默认状态
    this.success_data;// 成功传递的数据
    this.fail_reason;// 失败传递的数据
    // 执行成功
    let resolve = success_data => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';// 变动为成功状态
        this.success_data = success_data;// 把内容传递进success_data中
      }
    };
    // 执行失败
    let reject = fail_reason => {
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.fail_reason = fail_reason;
      }
    };
    // new Promise的第一个参数会当即执行
    executor(resolve, reject);
  }
  then(onFulFilled, onRejected) {
    if (this.status === 'fulfilled') {
      onFulFilled(this.success_data);
    }
    if (this.status === 'rejected') {
      onRejected(this.fail_reason);
    }
  }
}
复制代码

同一个实例能够被屡次then

class Promise {
  constructor(executor) {
    this.status = 'pending';// 默认状态
    this.success_data;// 成功传递的数据
    this.fail_reason;// 失败传递的数据
    this.onResolvedAry = [];// 存放成功的回调
    this.onRejectedAry = [];// 存放失败的回调
    // 执行成功
    let resolve = success_data => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';
        this.success_data = success_data;// 把内容传递进来
        this.onResolvedAry.forEach(item => item());// 遍历缓存列表,依次触发里面的回调函数
      }
    };
    // 执行失败
    let reject = fail_reason => {
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.fail_reason = fail_reason;
        this.onRejectedAry.forEach(item => item());
      }
    };
    // new Promise的第一个参数会当即执行
    executor(resolve, reject);
  }
  then(onFulFilled, onRejected) {
    if (this.status === 'fulfilled') {
      onFulFilled(this.success_data);
    }
    if (this.status === 'rejected') {
      onRejected(this.fail_reason);
    }
    // 异步执行时,status状态处于pending状态
    if (this.status === 'pending') {
      // 同一个实例能够被屡次then,在异步成功后调用resolve或者reject方法,以分别执行onResolvedAry,onRejectedAry两个数组
      // 添加到缓存列表、以供异步成功后执行的resolve或reject所循环调用
      this.onResolvedAry.push(onFulFilled(this.success_data));
      this.onRejectedAry.push(onRejected(this.fail_reason));
    }
  }
}
复制代码

.then方法是异步的

// 须要在then的状态判断下添加setTimeout(() => {}, 0)来模拟异步效果
复制代码

.then方法默认返回新的Promise(链式调用)

.then 方法中,状态判断下添加 - 返回新的 new Promise( 链式调用 ),在 promise 添加 setTimeout 以模拟异步执行数组

// 须要在then的状态判断下添加并返回一个新的Promise
class Promise {
  constructor(executor) {
    this.status = 'pending';// 默认状态
    this.success_data;// 成功传递的数据
    this.fail_reason;// 失败传递的数据
    this.onResolvedAry = [];// 存放成功的回调
    this.onRejectedAry = [];// 存放失败的回调
    // 执行成功
    let resolve = success_data => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';
        this.success_data = success_data;// 把内容传递进来
        this.onResolvedAry.forEach(item => item());
      }
    };
    // 执行失败
    let reject = fail_reason => {
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.fail_reason = fail_reason;
        this.onRejectedAry.forEach(item => item());
      }
    };
    executor(resolve, reject);
  }
  then(onFulFilled, onRejected) {
    let promise2;
    if (this.status === 'fulfilled') {
      promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
          onFulFilled(this.success_data);
        }, 0);
      });
    }
    if (this.status === 'rejected') {
      promise2 = new Promise((resolve, reject) => {
        setTimeout(() => {
          onRejected(this.fail_reason);
        }, 0);
      });
    }
    // 异步执行时,status处于pending状态
    // new Promise的第一个参数会当即执行,
    if (this.status === 'pending') {
      // 同一个实例能够被屡次then,在异步成功后调用resolve或者reject方法,以分别执行onResolvedAry,onRejectedAry两个数组
      promise2 = new Promise((resolve, reject) => {
        setTimeou(() => {
          this.onResolvedAry.push(onFulFilled(this.success_data));
          this.onRejectedAry.push(onRejected(this.fail_reason));
        }, 0);
      });
    }
  }
}
复制代码

.then方法中用户能够显示的返回Promise,并能够多层嵌套

截取其中的一段代码promise

then(onFulFilled, onRejected) {
  let promise2;
  if (this.status === 'fulfilled') {
    promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        let x = onFulFilled(this.success_data);
        resolvePromise(promise2, x, resovle, reject);
        // x为用户输入的返回值,p.then(data => { return "123" })
        // 若是是非promise的话,此时能够直接调用新的promise2的resolve方法
        // 若是是promise,那么就须要在then中拿到异步回来的参数,以调用promise2的resolve方法
        // 由于resolve或者reject中能够嵌套promise因此,因此咱们须要把这个判断抽离出一个函数,以方便递归调用本身
      }, 0);
    });
  }
}

resolvePromise(promise2, x, resolve, reject) {
  // typeof null === object
  if(x !== null && (typeof x === 'object' || typeof x === 'function')) {
    let then = x.then;
    // 判断then是不是函数,也许是一个对象
    if (typeof then === 'function') {
      then.call(x, (data) => {
        // 若是resolve中仍是一个promise,须要递归处理,直到出现不是promise值为止,而后调用promise2的resolve或reject。以返回到主流程的下一个then中
        resolvePromise(promise2, data, resolve, reject);
      }, (error) => {
        reject(error);
      });
    } else {
      // 若是不是一个函数,多是一个JSON
      resolve(x);
    }
  } else {
    // 若是不是promise就直接调用promise2的resolve
    resolve(x)
  }
}
复制代码

.then的代码

// 解析默认返回的promise和用户输入的promise之间的关系
function resolvePromise(promise2, x, resolve, reject) {
  // 这里面的resolve和reject都是promise2的
  // 判断x是不是Promise(核心)
  if (promise2 === x) {
    // 2.3.1 若是promise和x指向同一个对象,爆出TypeError类型错误,表示拒绝
    return reject(new TypeError('引用错误'));
  }
  // 2.3.2 若是x是一个对象或者函数,再去取then方法
  // typeof null === object
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    // 若是去检索x.then方法,抛出了异常,那么久应该reject异常抛出
    let onOff;// 防止成功以后再调取失败。。。为了兼容别人的Proimse
    try {// 防止取then时,报错
      let then = x.then;// 2.3.3.1 取x的then方法
      // 2.3.3.3 若是then是一个函数,就认为其实Promise
      if (typeof then === 'function') {
        // 让x.then执行。用户输入的promise执行then方法
        then.call(x, (data) => {
          if (onOff) return;
          onOff = true;
          // data有可能仍是一个Promise
          // 递归解析Promise
          resolvePromise(promise2, data, resolve, reject);
        }, (error) => {
          if (onOff) return;
          onOff = true;
          reject(error);
        });
      } else {
        resolve(x);
      }
    } catch (error) {
      if (onOff) return;
      onOff = true;
      reject(error);
    }
  } else {// 2.3.4 若是不是object或function 则直接fulfill 成功
    // 若是是一个普通值,则直接调用resolve把普通值传递进去
    resolve(x);
  }
}

class Promise {
  constructor(executor) {
    this.status = 'pending';
    this.success_value;
    this.fail_reason;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = data => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';// 变动状态
        this.success_value = data;// 传递值
        this.onResolvedCallbacks.forEach(item => item());
      }
    }
    let reject = reason => {
      if (this.status === 'pending') {
        this.status = 'rejected';
        this.fail_reason = reason;
        this.onRejectedCallbacks.forEach(item => item());
      }
    }
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onFulFilled, onRejected) {
    let promise2;
    // 添加链式操做
    if (this.status === 'fulfilled') {
      // 执行完成以后,返回一个新的Promise,以方便下一次链式调用
      promise2 = new Promise((resolve, reject) => {
        // 查看onFulFilled执行完的结果是什么?
        let x = onFulFilled(this.success_value);
        // 若是x返回的是一个普通值,则把这个普通只做为promise2成功的结果
        // 若是x是Promise,则取其结果,做为promise2成功的结果
        // 如今须要判断x和promise2的关系
        // promise2是then中执行完毕后的回调Proimse
        // x是 then中用户输入写的return值
        // 若是用户return的是一个普通值:那么须要传递給Promise2()的成功结果
        // 若是用户return的是一个Promise:那么须要断定是成功仍是失败

        // 解析promise,去x的结果,而后让promise2成功或者失败
        resolvePromise(promise2, x, resolve, reject);
      });
    }
    if (this.status === 'rejected') {
      promise2 = new Promise((resolve, reject) => {
        let x = onRejected(this.fail_reason);
        resolvePromise(promise2, x, resolve, reject);
      });
    }
    if (this.status === 'pending') {
      promise2 = new Promise((resolve, reject) => {
        // 存储值,在异步成功以后循环当前数组执行
        this.onResolvedCallbacks.push(() => {
          let x = onFulFilled(this.success_value);
          resolvePromise(promise2, x, resolve, reject);
        });
        this.onRejectedCallbacks.push(() => {
          let x = onRejected(this.fail_reason);
          resolvePromise(promise2, x, resolve, reject);
        });
      });
    }
    return promise2;
  }
}
复制代码

.catch方法

// catch就是then的第二个错误的简写
catch(onRejected) {
  return this.then(null, onRejected);
}
复制代码

Promise.resolve

Promise 上的静态方法 resolvereject ,直接调用静态方法中返回的新的 Promise 中的resolvereject便可缓存

Promise.resolve = function (value) {
  return new Promise((resolve, reject) => resolve(value));
}
Promise.reject = function (value) {
  return new Promise((resolve, reject) => reject(value));
}
复制代码

Promise.all([p1, p2, p3])

  1. 数组中全部的异步数据回来后,才执行 then 中成功回调
  2. 循环数组的 then 方法,若是 then 的数值 all 回来了,则调用新的 Promiseresolve,若是没有所有回来,则调 reject
  3. 若是数组中的异步直接调取了 reject 的,则直接调用新的 Promisereject
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let arr = [];
    let idx = 0;// 为了保证获取所有成功,来设置的索引.不能使用arr.length来判断,若是数组最后的异步先回来,那么此时arr和promises的长度就相等了 - 乱套了
    function processData(index, data) {
      // 和all的数组一一对应,arr数组和promises长度相等时成功
      arr[index] = data;
      // 給第二个复制,第一个的数值就是空的undefined,万一数组中的最后一个回来他们就都成功了 arr.length === promises.lenght
      idx++;
      if (idx === promises.length) {
        resolve(arr);
      }
    }
    for (let i = 0; i < promises.length; i++) {
      promises[i].then((data) => {
        // all 要根据数组的顺序来存放
        processData(i, data);
      }, reject);
    }
  });
}
复制代码

Promise.race

第一个参数中只要有一个异步数据回来,就执行异步

Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      // 只要有一个异步数据回来,誰回来的早就搞誰
      promises[i].then(resolve, reject);
    })
  });
}
复制代码

附:这篇博客 也许 想表达 promise 其实相对而言比较简单 (⊙﹏⊙)b函数

相关文章
相关标签/搜索