# Promise

# Promise 的作用

  • 解决并发问题 (同步多个异步方法的执行结果)
  • 链式调用问题 (先获取 name 再通过 name 获取 age 这种问题) 解决多个回调嵌套的问题

# Promise 简介

Promise 是一个类

  • 每次 new 一个 Promise 都需要传递一个执行器,执行器是立即执行的
  • 执行器函数中有两个参数 resolve reject
  • 默认 Promise 有三个状态 pending(等待) => resolve(成功) reject(失败)
  • 一旦成功不能失败,一旦失败不能成功
  • 每个 promise 都有一个 then 方法

promise 的链式调用

  • 普通值表示不是 promise 也不是错误(then 回调中返回的)会走下一个 then 的成功
  • 如果返回的是一个 promise 那么这个 promise 会执行,并且采用他的状态
  • 抛出错误 走then的失败方法
  • 返回一个新的 promise 来实现链式调用

# promise 基础用法实例

let p = new Promise((resolve, reject) => {
  resolve("success");
  throw new Error("失败"); //如果抛出异常也会执行成功
});
p.then(
  (data) => {
    console.log(data);
  },
  (err) => {
    console.log(err);
  }
);

let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("resolve在then之后执行"); // 发布
  }, 1e3);
});
// 订阅多个then方法
p2.then(
  (data) => {
    console.log(data);
  },
  (err) => {
    console.log(err);
  }
);
p2.then(
  (data) => {
    console.log(data);
  },
  (err) => {
    console.log(err);
  }
);

# promise 基础用法的实现

const PENDING = "PENGDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
console.log("---------------引入成功");
class Promise {
  constructor(executor) {
    this.value = undefined;
    this.reason = undefined;
    this.status = PENDING;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = value => {
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        this.onResolvedCallbacks.forEach(fn => fn()); // 发布 有可能resolve在then的后边执行,此时先将方法存放起来,状态改变为成功时依次执行这些方法(同一个示例订阅了多个then方法)
      }
    };
    let reject = reason => {
      if (this.status === PENDING) {
        this.value = reason;
        this.status = REJECTED;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };
    // 创建promise executor(执行器)会立即执行
    // 这里可能会发生异常
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    if (this.status === FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.status === REJECTED) {
      onRejected(this.reason);
    }
    if (this.status === PENDING) {
      this.onResolvedCallbacks.push(() => {
        // 外面在包一层函数 可以在这里再做一些其他的事 todo...
        onFulfilled(this.value);
      });
      this.onRejectedCallbacks.push(() => {
        // 外面在包一层函数 可以在这里再做一些其他的事 todo...
        onRejected(this.reason);
      });
    }
  }
}
// 导出当前类 commonjs定义的方式
module.exports = Promise;

# promise 链式调用用法实例

const fs = require("fs");
// 先看一看古老的用法
fs.readFile("name1.txt", "utf8", function(err, data) {
  if (err) {
    return console.error(err);
  }
  fs.readFile(data, "utf8", function(err, data) {
    if (err) {
      return console.error(err);
    }
    console.log(data);
  });
});
/**
 * desc  promise的链式调用
 * 1) 普通值表示不是promise 也不是错误(then回调中返回的)
 * 2)如果返回的是一个promise 那么这个promise会执行,并且采用他的状态
 */

// function readFile(...args) {
//   return new Promise((resolve, reject) => {
//     fs.readFile(...args, function(err, data) {
//       if (err) reject(err);
//       resolve(data);
//     });
//   });
// }
// readFile("name1.txt", "utf8")
//   .then(data => {
//     return readFile(data, "utf8");
//   })
//   .then(
//     data => {
//       console.log(data);
//     },
//     err => {
//       console.log(err);
//     }
//   );
const Promise = require("./promise的链式调用实现");
// 验证promise2 不能和 x是一个对象的例子
// let p = new Promise((resolve, reject) => {
//   resolve("hello");
// });
// // promise2
// let promise2 = p.then(
//   data => {
//     return promise2; // x
//   },
//   err => {
//     console.log(err);
//   }
// );
// promise2.then(
//   data => {
//     console.log(data);
//   },
//   err => console.log(err)
// );

// 验证resolve的也是一个promise的情况 即源码中的y也是一个promise的情况
let p2 = new Promise((resolve, reject) => {
  resolve(
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(
          new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve("嘿嘿嘿");
            }, 1000);
          })
        );
      }, 1000);
    })
  );
});
// promise2
let promise3 = p2
  .then(
    data => {
      console.log(data);
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(
            new Promise((resolve, reject) => {
              setTimeout(() => {
                resolve("嘿嘿嘿");
              }, 1000);
            })
          );
        }, 1000);
      });
    },
    err => {
      console.log(err);
    }
  )
  .then(
    data => {
      console.log("s:" + data);
    },
    err => console.log(err)
  );

# promise 链式调用实现

const PENDING = "PENGDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
console.log("---------------引入成功");
// promise处理函数
const resolvePromise = (promise2, x, resolve, reject) => {
  // 处理x的类型来决定是调用resolve还是reject
  // 必须要写的很严谨
  // promise2 和 x 不能是同一个对象 自己等待自己完成进入死循环 直接抛出错误
  if (promise2 === x) {
    return reject(
      new TypeError(`Chaining cycle detected for promise #<Promise>`)
    );
  }
  // 判断x是不是一个普通值 先认为他是一个promise
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    // typeof null === 'object'
    let called; // 默认情况下没有成功或者失败
    try {
      let then = x.then; // 先判断x里面是不是有then 如果有错误就抛出错误
      if (typeof then === "function") {
        // 这里就确定是promise了
        // x.then(()=>{},()=>{}) 这样会再次调用了一下x.then 会导致一些极端情况的问题
        then.call(
          x,
          y => {
            if (called) return; // 防止多次调用
            called = true;
            // y有可能还是一个promise 所以递归解析 直到可以解析为一个普通值了
            resolvePromise(promise2, y, resolve, reject);
          },
          r => {
            if (called) return; // 防止多次调用
            called = true;
            reject(r);
          }
        );
      } else {
        // 这里就是普通值 是个对象 没有成功或者失败 所以不用改变called的值
        resolve(x);
      }
    } catch (e) {
      if (called) return; // 防止多次调用
      called = true;
      reject(e); // 就抛出错误
    }
  } else {
    // 不是promise
    resolve(x);
  }
};
class Promise {
  constructor(executor) {
    this.value = undefined;
    this.reason = undefined;
    this.status = PENDING;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = value => {
      // 如果new Promise里的resolve直接返回一个新的promise时 递归调用resolve直到返回一个普通值
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }
      // 只有是PENDING状态的时候才能改变状态
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        this.onResolvedCallbacks.forEach(fn => fn()); // 发布 有可能resolve在then的后边执行,此时先将方法存放起来,状态改变为成功时依次执行这些方法(同一个示例订阅了多个then方法)
      }
    };
    let reject = reason => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };
    // 创建promise executor(执行器)会立即执行
    // 这里可能会发生异常
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : val => val;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : err => {
            throw err;
          };
    // then方法调用后应该返回一个新的promise
    let promise2 = new Promise((resolve, reject) => {
      // 应该在返回的promise中取到上一个promise的状态,来决定promise2走resolve还是reject
      if (this.status === FULFILLED) {
        // 当前的onFulfilled,onRejected不能在当前的上下文中执行,为了确保promise2的存在加上setTimeout改为异步
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value); // 当前/上一个 promise返回的值(可能是promise,可能是普通值,可能是个错误)
            resolvePromise(promise2, x, resolve, reject); // 处理x的类型来决定是调用resolve还是reject
          } catch (e) {
            reject(e);
          }
        });
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason); // 当前/上一个 promise返回的值(可能是promise,可能是普通值,可能是个错误)
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }
      if (this.status === PENDING) {
        this.onResolvedCallbacks.push(() => {
          // 外面在包一层函数 可以在这里再做一些其他的事 todo...
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value); // 当前/上一个 promise返回的值(可能是promise,可能是普通值,可能是个错误)
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          // 外面在包一层函数 可以在这里再做一些其他的事 todo...
          setTimeout(() => {
            try {
              let x = onRejected(this.reason); // 当前/上一个 promise返回的值(可能是promise,可能是普通值,可能是个错误)
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
      }
    });
    return promise2;
  }
  // catch就是then的语法糖
  catch(errCallback) {
    return this.then(null, errCallback);
  }
  // 静态方法 可以直接被 Promise.resolve()这种方式调用
  // 静态方法 是可以被类直接调用 不可以被示例调用,可以继承
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value);
    });
  }
  // 静态方法 可以直接被 Promise.reject()这种方式调用
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }
}

// 测试promise是否符合a+规范 全局安装 promises-aplus-tests包 执行 promises-aplus-tests 文件名
Promise.deferred = function() {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
// 导出当前类 commonjs定义的方式
module.exports = Promise;

# promise/A+验证通过的源码

// 自己再重新写几遍 2遍
const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";
const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) {
    return reject(new TypeError(`自己等自己,等傻了吧#<promise>`));
  }
  if ((typeof x === "object" && x !== null) || typeof x === "function") {
    let called;
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          r => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
};
class Promise {
  constructor(executor) {
    this.value = undefined;
    this.reason = undefined;
    this.status = PENDING;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = value => {
      if (value instanceof Promise) {
        return value.then(resolve, reject);
      }
      if (this.status === PENDING) {
        this.value = value;
        this.status = FULFILLED;
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };
    let reject = reason => {
      if (this.status === PENDING) {
        this.reason = reason;
        this.status = REJECTED;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : val => val;
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : err => {
            throw err;
          };
    let promise2 = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        });
      }
      if (this.status === PENDING) {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          });
        });
      }
    });
    return promise2;
  }
  catch(errCallback) {
    return this.then(null, errCallback);
  }
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value);
    });
  }
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }
}

Promise.deferred = function() {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
module.exports = Promise;

# promise.all 的实现

// promise.all 全部  处理多个异步的并发问题
let fs = require("fs").promises;

// 全部完成才算完成,如果有一个失败 就失败
// Promise.all 是按照顺序执行的
const isPromise = value => {
  if (
    (typeof value === "object" && value !== null) ||
    typeof value === "function"
  ) {
    return typeof value.then === "function";
  }
  return false;
};
// 开始写all方法
Promise.all = promises => {
  return new Promise((resolve, reject) => {
    let arr = [];
    let i = 0;
    let processData = (index, data) => {
      arr[index] = data;
      if (++i === promises.length) {
        resolve(arr);
      }
    };
    for (let i = 0; i < promises.length; i++) {
      let current = promises[i];
      if (isPromise(current)) {
        current.then(data => {
          processData(i, data);
        }, reject);
      } else {
        processData(i, current);
      }
    }
  });
};
Promise.all([
  fs.readFile("./name.txt", "utf8"),
  1,
  2,
  3,
  fs.readFile("./age.txt", "utf8")
]).then(
  data => {
    console.log(data);
  },
  err => {
    console.log(err);
  }
);