Loading

深度学习Promise a+ 规范

Promise A+ 规范

Promise表示一个异步操作的最终结果。与Promise最主要的交互方法是通过将函数传入它的then方法从而获取得Promise最终的值或Promise最终最拒绝(reject)的原因。

术语

promise是一个包含了兼容promise规范then方法的对象或函数
thenable是一个包含了then方法的对象或者函数
value是任何JavaScript值
execption 是有throw表达式抛出来的值
reason是一个用于描述Promise被拒绝的原因

要求

Promise 是一个类 无需考虑兼容问题
当使用promise时 有一个执行器 executor 会立即执行

promise有三个状态,pendding,rejected,fulfilled

定义状态

一个promise必须处在其中之一的状态

  • 如果是pendding状态 则promise 可以转换到fulfilled或者rejected状态
  • 如果是fulfill状态,则promise不能转换成任何状态,而且必须有一个值
  • 如果是rejected状态,则promise不能转换成任何状态,而且必须有一个原因
const PEDDING = "PEDDING";
const REJECTED = "REJECTED";
const FULFILLED = "FULFILLED";

Promise的基本代码结构

value表示成功的值
reason表示被拒绝的原因
executor new Promise接受一个立即执行函数, resolve,reject作为其参数

class Promise {
  constructor(executor) { // new Promise 接受一个执行器
    this.value = undefined; // 成功的值
    this.reason = undefined; // 失败的值
     const resolve = (value) => {
      // 如果是pendding状态 则promise 可以转换到fulfilled或者rejected状态
      if (this.status === PEDDING) {
        this.value = value;
        this.status = FULFILLED; // 把状态置成 FULFILLED
      }
    };

    const reject = (reason) => {
      // 如果是pendding状态 则promise 可以转换到fulfilled或者rejected状态
      if (this.status === PEDDING) {
        this.reason = reason;
        this.status = REJECTED; // 把状态置成 REJECTED
      }
    };

    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
 // ....
}

then 方法

一个Promise必须提供一个then方法来获取其值或原因。

promise.then(onFulfilled, onRejected)

规范

  • onFulfilledonRejected都是可选参数。如果onFulfilled不是一个函数,则可以忽略;如果onRejected不是一个函数,也可以进行忽略
  • 如果onFulfilled是一个函数, 它必须在promise fulfilled 之后调用, 且promise的value是它的第一个参数; 它不能在promise fulfilled之前调用,而且只能调用一次
  • 如果onRejected是一个函数,它必须在promise rejected 之后调用,且promise的reason是它的第一个参数, 它也不能在promise rejected之前调用,并且也只能调用一次。
  • onFulfilledonRejected值允许在execution contet栈仅包含平台代码时运行。
  • onFulfilledonRejected必须被当做函数调用。
  • 一个promise,它的then方法可以多次调用,
    • promisefulfilled后,所有onFulfilled都必须按照其注册顺序执行
    • promie rejected 后,所有onRejected也都必须按照其之策顺序执行
  • then必须返回一个promise
promise2 = promise1.then(onFulfilled,onRejected)

constructor(){
 // ....
  this.onFulfilledCallbacks = [];
  this.onRejectedCallbacks = [];
  const resolve = (value) => {
      // 如果是pendding状态 则promise 可以转换到fulfilled或者rejected状态
      if (this.status === PEDDING) {
        this.value = value;
        this.status = FULFILLED; // 把状态置成 FULFILLED
        this.onFulfilledCallbacks.forEach((fn) => fn()); // 按注册时的顺序执行
      }
    };

    const reject = (reason) => {
      // 如果是pendding状态 则promise 可以转换到fulfilled或者rejected状态
      if (this.status === PEDDING) {
        this.reason = reason;
        this.status = REJECTED; // 把状态置成 REJECTED
        this.onRejectedCallbacks.forEach((fn) => fn()); // 按注册时的顺序执行
      }
    };
}


// 
then(onFulfilled, onRejected) {
    // 1. then方法接受两个参数
    // 验证onFulfilled 和 onRejected 的类型
    // 5 onRejected 和 onFulfilled 必须当做函数调用
    // 值穿透
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
    onRejected = typeof onRejected === "function" ? onRejected : (v) => {throw v};

    // 实现链式调用

    let promise2 = new Promise((resolve, reject) => {
      // 订阅方法
      if (this.status === FULFILLED) {
        // 2 onFulfilled 必须在 promise fulilled之后调用。 且promise的value是其第一个参数
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            // 7.1 此时x可能是一个promise, 如果是promise 需要看一下promise是成功还是失败。 .then,  如果成功则吧
            // 成功的结果调用promise2的resolve传递进去, 失败则同理
            // 总结 x的值 决定是调用promise2的resolve还是reject, 如果是promise,则取他的状态,如果是普通值
            // 就直接调用resolve

            resolvePromise(promise2, x, resolve, reject); // 解析promise流程
          } catch (e) {
            reject(e);
          }
        }, 0);
      }

      if (this.status === REJECTED) {
        // 3 onRejected 必须 在reject之后调用 , 且promise的reason为它的第一个参数
        // 失败调用失败的方法
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
        -
      // 4 onRejected 和 onFulfilled只允许在 execution context 栈 仅包含你平台代码时运行

      if (this.status === PEDDING) {
        // 6.1 把onFulfilled 缓存起来, 当resolve时 按照其添加顺序执行
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        // 6.2 把onRejected 缓存起来  在调用reject时再按照其添加顺序执行
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    // 7. then 必须返回一个promise
    return promise2;
  }

promise解析流程

/**
 * promise解析过程: 是一个以promise和一个值作为参数的抽象过程, 可以表示为[[Resolve]](promise,x)
 * 1. 如果promise和x的值指向同一个值, 使用TypeError作为原因将promise拒绝
 * 2. 如果x是一个promise 则采用其状态
 *    1. 如果x是pendding状态,promise必须保持pendding走到x fulfilled或者rejected
 *    2. 如果x是fulfilled状态,将x的值用于fulfilled promise
 *    3. 如果x是rejected状态,将x的值用于reject promise
 * 3. 如果x是一个对象或者一个函数
 *    1. 将then赋值x.then
 *    2. 如果在取x.then值时抛出了异常, 则以这个异常为原因将promise拒绝
 *    3. 如果then是一个函数,以x为this调用then函数, 且第一个参数是resolvePromise,第二个参数是rejectPromise
 *        1. 当resolvePromise被以y为参数调用,执行[[Resolve]](promise,y)
 *        2. 当rejectPromise被以r为参数调用,则以r为原因将promise拒绝
 *        3. 控制其resolvePromise,rejectPromise只调用一次
 *        4. 如果在调用then时抛出了异常
 *            1. 如果resolvePromise或rejectPromise已经被调用,则忽略它
 *            2. 否则,以e为reason将其promise拒绝
 *    4. 如果then不是一个函数, 则以x为值fulfill promise
 * @param {*} promise2
 * @param {*} x
 * @param {*} resolve
 * @param {*} reject
 * @returns
 */
function resolvePromise(promise2, x, resolve, reject) {
  // 核心流程
  if (promise2 === x) {
    // 1. 如果promise和x的值指向同一个值, 使用TypeError作为原因将promise拒绝. 避免循环引用
    return reject(new TypeError("error"));
  }

  //自己写的Promise要与别人的promise兼容 考虑不是自己写的promise情况
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    let called = false;
    try {
      // 别人的promise可能调用成功后 还能调用失败, 取值时可能发生异常
      //规范 2.3.3.1
      let then = x.then;  
      if (typeof then === "function") {
        then.call(
          x, // 3. 以x为this 调用then
          (y) => {
            if (called) {
              return;
            }
            called = true;
            resolvePromise(promise2, y, resolve, reject); // 递归解析 直到不是promise为止
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        // 规范 2.3.3.4
        resolve(x);
      }
    } catch (e) {
      // 3-2. 如果在取x.then值时抛出了异常, 则以这个异常为原因将promise拒绝
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    // 4 如果不是一个函数, 则以x为值 fulfilled promise
    // 规范 2.3.4,x 为基本类型
    resolve(x);
  }
}

then的值穿透

如果没有穿onFulfilled或者onRejected 就默认设置v=>v

new Promise((resolve)=>{
    resolve(1)
}).then().then().then().then(console.log)
 // ...
 onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
 onRejected = typeof onRejected === "function" ? onRejected : (v) => {throw v};
 // ...

catch

Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数

// ....
catch (errorFn){
  return this.then(null,errorFn)
}
//....

finally

无论当前 Promise 是成功还是失败,调用finally之后都会执行finally中传入的函数,并且将值原封不动的往下传。

//....
finally(callback){
  return this.then(
    data=> Promise.resolve(callback()).then(()=> data),
    error=> Promise.resolve(callback()).then(()=> {throw errror})
  )
}
//...

Promise.resolve 方法

Promise.resolve是一个静态方法, 它返回一个promise的一个成功态。

//......
static resolve(value){
   return new Promise((resolve,reject)=>{
      resolve(value)
   })
}
//....
//useage
Promise.resolve('success').then(console.log)

Promise.reject 方法

Promise.reject 也是一个静态方法, 它返回promise的一个拒绝态。

//.....
static reject(reason){
 return new Promise((resolve, reject)=>{
    reject(reject)
  })
}
//...

// useage

Promise.reject('error').catch(console.log)

Promise.all

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例.
会等待所有的promise全部完成,返回一个新的promise。 当其中有一个promise失败,那么这个promise就失败了。
多个异步并发执行。
如果参数中有一个promise失败,那么Promise.all返回的promise对象失败。
在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组

const promises = Promise.all([p1,p2,p3])

Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。且返回的每个成员都是 Promise 实例。

static all(promises){
  return new Promise((resolve,reject)=>{
    let result = [];
    let times = 0;
    function prcessPromise(index, value){
      result[index] = value;
      if(++times === promises.length) return resolve(result)
    }
    for(let i = 0; i< promise.length; i++){
       let p = promises[i]
        if(p && typeof p.then === 'function'){
           p.then(
             data=> processPromise(i, data),
             reject // 当有一个失败时, 就直接调用reject
           );
        }else{
          prcessPromise(i,p)
        }
    }
 })
}

Promise.race

只要有一个 promise 执行完,直接 resolve 并停止执行

static race(promises){
  return new Promise((resolve,reject)=>{
     for(let i = 0; i< promises.length; i++){
       let p = promise[i];
        if(p && typeof p.then === 'function'){
          p.then(resolve,reject)
        }else{
          resolve(p)
        }
     }
  })
}

Promise.allsettled

等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。跟Promise.all的区别时, Promise.allSettled是包含数组中的promise成功的还是失败的,并一起返回。
接受的结果与入参时的promise实例一一对应,且结果的每一项都是一个对象,告诉你结果和值,对象内都有一个属性叫status,用来明确知道对应的这个promise实例的状态(fulfilledrejected),fulfilled时,对象有value属性,rejected时有reason属性,对应两种状态的返回值。

const resolved = Promise.resolve(100)
const rejected = Promise.reject(-100)
const allSettle = Promise.allSettled([resolved,rejected]);

allSettle.then(console.log)

//[
//  { status: 'fulfilled', value: 100 },
//  { status: 'rejected', reason: -100 }
//]

实现

static allSettled(promises) {
  return new Promise((resolve, reject) => {
    const result = [];
    let times = 0;
    function processPromise(index, value) {
      result[index] = value;
      if (++times === promises.length) return resolve(result);
    }
    for (let i = 0; i < promises.length; i++) {
      const p = promises[i];
      if (p && typeof p.then === "function") {
        p.then(
          (value) => processPromise(i, value),
          (error) => processPromise(i, error)
        );
      } else {
        processPromise(i, p);
      }
    }
  });
}

promise/deferred

什么是promise/deferred 模式

promise/deferred 模式是,根据promise/A 或者它的增强修改版promise/A+ 规范 实现的promise异步操作的一种实现方式。

异步的广度使用使得回调,嵌套出现,但是一但出现深度的嵌套,就会让coding的体验变得相当不愉快,而且代码后期的维护也是相当吃力的。promise/deferred模式的出现,会在一定程度上缓解这个问题。接下来我会根据promise/a 规范来介绍promise/deferred模式。

实现

static deferred(){
  const dfd = {};
  dfd.promise = new Promise((resolve,reject)=>{
    dfd.resolve= resolve;
    dfd.reject = reject;
  })
  return dfd
}

//useage
const { log } = require("console");
const fs = require("fs");
function readFile(filePath) {
  const dfd = Promise.defeered();
  log(dfd);
  fs.readFile(filePath, "utf8", function (err, data) {
    if (err) return dfd.reject(err);
    dfd.resolve(data);
  });
  return dfd.promise;
}
readFile("./a.js").then(console.log);

完整代码

const PEDDING = "PEDDING";
const REJECTED = "REJECTED";
const FULFILLED = "FULFILLED";
/**
 * promise解析方法
 * promise解析过程: 是一个以promise和一个值作为参数的抽象过程, 可以表示为[[Resolve]](promise,x)
 * 1. 如果promise和x的值指向同一个值, 使用TypeError作为原因将promise拒绝
 * 2. 如果x是一个promise 则采用其状态
 *    1. 如果x是pendding状态,promise必须保持pendding走到x fulfilled或者rejected
 *    2. 如果x是fulfilled状态,将x的值用于fulfilled promise
 *    3. 如果x是rejected状态,将x的值用于reject promise
 * 3. 如果x是一个对象或者一个函数
 *    1. 将then赋值x.then
 *    2. 如果在取x.then值时抛出了异常, 则以这个异常为原因将promise拒绝
 *    3. 如果then是一个函数,以x为this调用then函数, 且第一个参数是resolvePromise,第二个参数是rejectPromise
 *        1. 当resolvePromise被以y为参数调用,执行[[Resolve]](promise,y)
 *        2. 当rejectPromise被以r为参数调用,则以r为原因将promise拒绝
 *        3. 控制其resolvePromise,rejectPromise只调用一次
 *        4. 如果在调用then时抛出了异常
 *            1. 如果resolvePromise或rejectPromise已经被调用,则忽略它
 *            2. 否则,以e为reason将其promise拒绝
 *    4. 如果then不是一个函数, 则以x为值fulfill promise
 * @param {*} promise2
 * @param {*} x
 * @param {*} resolve
 * @param {*} reject
 * @returns
 */
function resolvePromise(promise2, x, resolve, reject) {
  // 核心流程
  if (promise2 === x) {
    // 1. 如果promise和x的值指向同一个值, 使用TypeError作为原因将promise拒绝
    return reject(new TypeError("error"));
  }

  //自己写的Promise要与别人的promise兼容 考虑不是自己写的promise情况
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    let called = false;
    try {
      // 别人的promise可能调用成功后 还能调用失败, 取值时可能发生异常
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x, // 3. 以x为this 调用then
          (y) => {
            if (called) {
              return;
            }
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      // 3-2. 如果在取x.then值时抛出了异常, 则以这个异常为原因将promise拒绝
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    // 4 如果不是一个函数, 则以x为值 fulfilled promise
    resolve(x);
  }
}

class Promise {
  constructor(executor) {
    this.value = undefined; // 成功的原因
    this.status = PEDDING; // promise的状态
    this.reason = undefined; // 失败的原因
    this.onFulfilledCallbacks = []; // 存放成功的回调方法
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.status === PEDDING) {
        if (value instanceof Promise) {
          return value.then(resolve, reject);
        }
        this.value = value;
        this.status = FULFILLED;
        // 6.1 当promise fulilled 后 所有onFulfilled 必须按照其注册顺序执行
        this.onFulfilledCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.status === PEDDING) {
        this.reason = reason;
        this.status = REJECTED;
        // 6.2 当promise rejected后, 所有onRejected 必须按照其注册顺序执行
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    // 1. then方法接受两个参数
    // 验证onFulfilled 和 onRejected 的类型
    // 5 onRejected 和 onFulfilled 必须当做函数调用
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
    onRejected = typeof onRejected === "function" ? onRejected : (v) => v;

    // 实现链式调用

    let promise2 = new Promise((resolve, reject) => {
      // 订阅方法
      if (this.status === FULFILLED) {
        // 2 onFulfilled 必须在 promise fulilled之后调用。 且promise的value是其第一个参数
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            // 7.1 此时x可能是一个promise, 如果是promise 需要看一下promise是成功还是失败。 .then,  如果成功则吧
            // 成功的结果调用promise2的resolve传递进去, 失败则同理
            // 总结 x的值 决定是调用promise2的resolve还是reject, 如果是promise,则取他的状态,如果是普通值
            // 就直接调用resolve
            resolvePromise(promise2, x, resolve, reject); // 解析promise流程
          } catch (e) {
            reject(e);
          }
        }, 0);
      }

      if (this.status === REJECTED) {
        // 3 onRejected 必须 在reject之后调用 , 且promise的reason为它的第一个参数
        // 失败调用失败的方法
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
      // 4 onRejected 和 onFulfilled只允许在 execution context 栈 仅包含你平台代码时运行

      if (this.status === PEDDING) {
        // 6.1 把onFulfilled 缓存起来, 当resolve时 按照其添加顺序执行
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        // 6.2 把onRejected 缓存起来  在调用reject时再按照其添加顺序执行
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
    // 7. then 必须返回一个promise
    return promise2;
    // - .如果 onFulfilled 或者 onRejected 返回了值x , 则执行promise的解析流程。
    // - .如果onFulfilled 或者 onRejected抛出异常,则promise2应当以e为reason被拒绝
    // - .如果onFulfilled不是一个函数且promise1已经fulfilled,则promise2必须以promise1的值fulfilled
    // - .如果onRejected不是一个函数 且promise1已经rejected, 则promise2必须以相同的reason被拒绝
  }

  catch(errorFn) {
    return this.then(null, errorFn);
  }

  // 无论是成功还是失败 都会执行
  // 可以返回一个promise
  finally(cb) {
    return this.then(
      (data) => {
        return Promise.resolve(cb()).then(() => data);
      },
      (err) => {
        return Promise.resolve(cb()).then(() => {
          throw err;
        });
      }
    );
  }

  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value);
    });
  }

  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }

  /**
   * 等所有的promise全部完成
   * 但当其中有一个失败了 那么这个promise就失败了
   * 多个异步 并发请求
   */
  static all(promises) {
    return new Promise((resolve, reject) => {
      let result = [];
      let times = 0;
      const processSucccess = (index, val) => {
        // 会出现某些then结果速度快些  所以采用result[index]
        result[index] = val;
        if (++times === promises.length) {
          resolve(result);
        }
      };
      for (let i = 0; i < promises.length; i++) {
        const p = promises[i];
        if (p && typeof p.then === "function") {
          p.then(
            (data) => processSucccess(i, data),
            // 如果有一个失败了 就执行失败
            reject
          );
        } else {
          processSucccess(i, p);
        }
      }
    });
  }

  /**
   * 其中一个完成了 但是剩下的还会继续执行
   */
  static race(promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        const p = promises[i];
        if (p && typeof p.then === "function") {
          p.then(resolve, reject);
        } else {
          resolve(p);
        }
      }
    });
  }

  static deferred() {
    const dfd = {};
    dfd.promise = new Promise((resolve, reject) => {
      dfd.resolve = resolve;
      dfd.reject = reject;
    });
    return dfd;
  }

  static allSettled(promises) {
    return new Promise((resolve, reject) => {
      const result = [];
      let times = 0;
      function processPromise(index, value) {
        result[index] = value;
        if (++times === promises.length) return resolve(result);
      }
      for (let i = 0; i < paromise.length; i++) {
        const p = promises[i];
        if (p && typeof p.then === "function") {
          p.then(
            (value) => processPromise(i, value),
            (error) => process(i, error)
          );
        } else {
          processPromise(i, p);
        }
      }
    });
  }
}

英文链接

posted @ 2021-10-08 15:46  vincent_cyi  阅读(124)  评论(0编辑  收藏  举报