javascriptの手書きはpromiseです.

50243 ワード

プロミス
promiseの3つの状態:pending(未完成)、fulfilled(完了)、reject(拒否)
よくある操作:
new Promise((resolve, reject) => {
  //    
  this.$axios
    .get("/", { params: { id: id } })
    .then(res => {
      resolve(res); //         
    })
    .catch(err => {
      reject(err); //   
    });
})
  .then(resData => {
    //do something
    console.log(resData);
  })
  .catch(err => {
    console.log(err);
  });
promiseコンストラクタの中で二つの関数をパラメータとして受信しました.一つのreolveと一つのrejectは成功すれば成功データに戻ります.
class Promise2 {
  constructor(fn) {
    this._queue = [];
    this._succ_mes = null;
    this._error_mes = null;
    this.status = "";

    fn(
      //        
      (...arg) => {
        // resolve
        this._succ_mes = arg;
        this.status = "succ";
      },
      (...arg) => {
        // reject
        this._error_mes = arg;
        this.status = "err";
      }
    );
  }

  then(fn1, fn2) {
    // then       
    if (this.status === "succ") {
      fn1(...this._succ_mes);
    } else if (this.status === "err") {
      if (fn2) {
        // then          ,           reject  ,            
        fn2(...this._error_mes);
        return;
      }
      fn1(...this._succ_mes);
    } else {
      this._queue.push({ fn1, fn2 });
    }
  }
}
以上の簡単なpromiseを実現しました.成功状態に戻った値は、失敗状態値(124;then関数)の2つの関数パラメータの戻り値を返します.
次にthenのチェーンコールを追加します.
class Promise2 {
  constructor(fn) {
    this._queue = [];
    this._succ_mes = null;
    this._error_mes = null;
    this.status = "";
    this.promise3 = null;
    fn(
      //        
      (...arg) => {
        // resolve
        this._succ_mes = arg;
        this.status = "succ";
        this._queue.forEach(({ fn1 }) => fn1());
      },
      (...arg) => {
        // reject
        this._error_mes = arg;
        this.status = "err";
        this._queue.forEach(({ fn2 }) => fn2());
      }
    );
  }

  then(fn1, fn2) {
    // then       

    this.promise3 = new Promise2((resolve, reject) => {
      if (this.status === "succ") {
        resolvePromise(this.promise3, fn1(...this._succ_mes), resolve, reject);
      } else if (this.status === "err") {
        if (fn2) {
          // then          ,           reject  ,            

          resolvePromise(
            this.promise3,
            fn2(...this._error_mes),
            resolve,
            reject
          );
          return;
        }
        resolvePromise(this.promise3, fn1(...this._succ_mes), resolve, reject);
      } else {
        this._queue.push({
          fn1: resolvePromise(
            this.promise3,
            fn1(...this._succ_mes),
            resolve,
            reject
          ),
          fn2: resolvePromise(
            this.promise3,
            fn2(...this._error_mes),
            resolve,
            reject
          )
        });
      }
    });

    return this.promise3; //      
  }
}

function resolvePromise(promise3, value, resolve, reject) {
  if (promise3 === value) {
    reject(new TypeError("Promise       "));
  }
  if (
    value !== null &&
    (typeof value === "object" || typeof value === "function")
  ) {
    try {
      let then = value.then;
      if (typeof then === "function") {
        then.call(
          value,
          y => {
            resolve(y);
          },
          x => {
            reject(x);
          }
        );
      }
    } catch (err) {
      reject(err);
    }
  } else {
    resolve(value);
  }
}
catchを追加
class Promise2 {
  constructor(fn) {
    this._queue = [];
    this._succ_mes = null;
    this._error_mes = null;
    this.status = "";
    this.promise3 = null;

    //        
    let resolve = (...arg) => {
      // resolve
      this._succ_mes = arg;
      this.status = "succ";
      this._queue.forEach(({ fn1 }) => fn1());
    };
    let reject = (...arg) => {
      // reject
      this._error_mes = arg;
      this.status = "err";
      this._queue.forEach(({ fn2 }) => fn2());
    };

    try {
      fn(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(fn1, fn2) {
    // then       
    fn1 = typeof fn1 === "function" ? fn1 : value => value;
    fn2 =
      typeof fn2 === "function"
        ? fn2
        : err => {
            throw err;
          };

    this.promise3 = new Promise2((resolve, reject) => {
      if (this.status === "succ") {
        try {
          resolvePromise(
            this.promise3,
            fn1(...this._succ_mes),
            resolve,
            reject
          );
        } catch (e) {
          reject(e);
        }
      } else if (this.status === "err") {
        if (fn2) {
          // then          ,           reject  ,            
          try {
            resolvePromise(
              this.promise3,
              fn2(...this._error_mes),
              resolve,
              reject
            );
          } catch (e) {
            reject(e);
          }

          return;
        }
        resolvePromise(this.promise3, fn1(...this._succ_mes), resolve, reject);
      } else {
        try {
          this._queue.push({
            fn1: resolvePromise(
              this.promise3,
              fn1(...this._succ_mes),
              resolve,
              reject
            ),
            fn2: resolvePromise(
              this.promise3,
              fn2(...this._error_mes),
              resolve,
              reject
            )
          });
        } catch (e) {
          console.log(e);
        }
      }
    });

    return this.promise3; //      
  }
  catch(fn) {
    this.status === "err";
    return this.then(null, fn);
  }
}
非同期処理を追加
then(fn1, fn2) {
    // then       
    fn1 = typeof fn1 === "function" ? fn1 : value => value;
    fn2 =
      typeof fn2 === "function"
        ? fn2
        : err => {
            throw err;
          };

    this.promise3 = new Promise2((resolve, reject) => {
      // console.log(promise3);
      if (this.status === "succ") {
        setTimeout(() => {
          try {
            resolvePromise(
              this.promise3,
              fn1(...this._succ_mes),
              resolve,
              reject
            );
          } catch (e) {
            reject(e);
          }
        }, 0);
      } else if (this.status === "err") {
        try {
          if (fn2) {
            // then          ,           reject  ,            

            resolvePromise(
              this.promise3,
              fn2(...this._error_mes),
              resolve,
              reject
            );

            return;
          }
          setTimeout(() => {
            resolvePromise(
              this.promise3,
              fn1(...this._succ_mes),
              resolve,
              reject
            );
          }, 0);
        } catch (e) {
          reject(e);
        }
      } else {
        setTimeout(() => {
          try {
            this._queue.push({
              fn1: resolvePromise(
                this.promise3,
                fn1(...this._succ_mes),
                resolve,
                reject
              ),
              fn2: resolvePromise(
                this.promise3,
                fn2(...this._error_mes),
                resolve,
                reject
              )
            });
          } catch (e) {
            reject(e);
          }
        }, 0);
      }
    });

    return this.promise3; //      
  }