promise 實現思路過程

寫一個demo

const demo = new Promise((resolve,reject)=>{
  resolve('sajdhgas')
})

demo.then(a =>{console.log(a,'console')})

複製代碼

什麼是promise

偷懶用的mdn的圖,見諒啊,各位大佬 (- . -)javascript

第一步: then catch 原型鏈方法 和 this指向

  1. then:接收兩個函數 resolve reject
  2. catch: 接收一個函數 callback ,callback的參數爲 executor,resolve,reject 三個回調的 內部錯誤捕獲處理
  3. then方法和catch方法 都返回一個新的 promise對象
class PromiseDemo {
  constructor(executor){
      this.resolveResult = null; 
      this.rejectResult = null; 

      const resolve = (a) =>{ 
        this.resolveResult = a;
      }
      const reject = (a) =>{ 
        this.rejectResult = a; 
      }

      try{
        executor(resolve);
      }catch(e){
        reject(e)
      }
  }
  then = (onResolve,onReject) =>{ 
    if(onReject){
      onReject(this.rejectResult)
    }else{
      onResolve(this.resolveResult)
    }
    return this
  }
  catch = onReject =>{
    this.then(null,onReject)
  } 
} 
const demo = new PromiseDemo((resolve,reject)=>{
 //resolve('sajdhgas')
  aaa
})

demo.then(a =>{console.log(a,'then')}).catch(a =>{console.log(a.message,'then')})

複製代碼

第二步: Promise 的狀態一旦改變,就永久保持該狀態,不會再變了

const PENDING = "pending";
const FULFILLED = "fullilled";
const REJECTED = "rejected";

class PromiseDemo {
  constructor(executor) {
    this.state = PENDING;

    this.resolveResult = null;
    this.rejectResult = null;

    const resolve = a => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.resolveResult = a;
      }
    };
    const reject = a => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.rejectResult = a;
      }
    };

    try {
      executor(resolve);
    } catch (e) {
      reject(e);
    }
  }
  then = (onResolve, onReject) => {
    if (onReject) {
      onReject(this.rejectResult);
    } else {
      onResolve(this.resolveResult);
      return this;
    }
  };
  catch = onReject => {
    this.then(null, onReject);
    return this;
  };
}

const demo = new PromiseDemo((resolve, reject) => {
  resolve("sajdhgas");
  resolve("sajdhgas1222");
});
demo
  .then(a => {
    console.log(a, "then");
  })
  .catch(a => {
    console.log(a, "catch");
  });

複製代碼

第三步: 異步回調

給promise內部加一個狀態鎖 statejava

對於異步: 在等待過程當中,把onResolve存起來,在resolve回調裏處理調用
對於同步: 在執行executor的時候把resolve的值存起來,在then裏直接調用es6

const PENDING = "pending";
const FULFILLED = "fullilled";
const REJECTED = "rejected";

class PromiseDemo {
  constructor(executor) {
    this.state = PENDING;

    this.resolveResult = null;
    this.rejectResult = null;

    this.onReject = null;
    this.onResolve = null;
 
    const resolve = a => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.resolveResult = a;
        this.onResolve(a);
      }
    };
    const reject = a => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.rejectResult = a;
      }
    };

    try {
      executor(resolve);
    } catch (e) {
      reject(e);
    }
  }

  then = (onResolve, onReject) => {
    switch(this.state){
      case PENDING:
      this.onResolve = () => onResolve(this.resolveResult);
      return this;
      case FULFILLED:
      onResolve(this.resolveResult);
      return this;

      case REJECTED:
      this.onResolve = () => onResolve(this.resolveResult);
      return this;

      default: 
      break;
    }
  };
  catch = onReject => {
    this.then(null, onReject);
    return this;
  };
}

const demo = new PromiseDemo((resolve, reject) => {
  setTimeout(() => {
    resolve("sajdhgas");
  }, 1000);
});

demo.then(a => {
  console.log(a, "then");
}); 
複製代碼

第四步: 返回一個新的 promise對象 完成鏈式調用

then方法和catch方法 都返回一個新的 promise對象,Promise 對象的錯誤具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。json

捕獲onReslove函數的返回值 並交給resolvePromise 統一處理

const PENDING = "pending";
const FULFILLED = "fullilled";
const REJECTED = "rejected";

class PromiseDemo {
  constructor(executor) {
    this.state = PENDING;

    this.resolveResult = null;
    this.rejectResult = null;

    this.onReject = null;
    this.onResolve = null;

    const resolve = a => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.resolveResult = a;
        this.onResolve();
      }
    };
    const reject = a => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.rejectResult = a;
        this.onReject();
      }
    };

    try {
      executor(resolve);
    } catch (e) {
      reject(e);
    }
  }

  then = (onResolve, onReject) => {
    const promise2 = new PromiseDemo((resolve, reject) => {
      switch (this.state) {
        case PENDING:
          this.onResolve = () => {
            // 這裏能夠打印到異步 promise的onResolve結果
            // 獲取onResolve返回值 判斷返回值類型
            const fulfilledResult = onResolve(this.resolveResult);
            resolvePromise(promise2,fulfilledResult, resolve, reject);
          };
          this.onReject = () => {
            const rejectedResult = onReject(this.rejectResult);
            resolvePromise(promise2,rejectedResult, resolve, reject);
          };
          break;

        case FULFILLED:
          const fulfilledResult = onResolve(this.resolveResult);
          resolvePromise(promise2,fulfilledResult, resolve, reject);
          break;

        default:
          const rejectedResult = onReject(this.rejectResult);
          resolvePromise(promise2,rejectedResult, resolve, reject);
          break;
      }
    });

    return promise2;
  };
  catch = onReject => {
    this.then(null, onReject);
  };
}



const resolvePromise = (result, resolve, reject) => {
  resolve(result, "a");
};

const demo = new PromiseDemo((resolve, reject) => {
  // resolve("sajdhgas1");
  setTimeout(() => {
    resolve("sajdhgas2");
  }, 1000);
});

const a = demo
  .then(a => {
    console.log(a, "then1");
    return "json.post";
  })
  .then(a => {
    console.log(a, "then2");
  });

複製代碼

resolvePromise(promise2 , result , resolve,reject)

功能:數組

  • 將這個promise2返回的值傳遞到下一個then中
  • 若是返回一個普通的值,則將普通的值傳遞給下一個then中 分析
  1. 若是返回值是一個promise,則獲取promise.then 的返回值 再執行一遍resolvePromise 拋出結果給下一個then
  2. 若是返回值和後面返回的是同一個promise,會陷入死循環
  3. 若是是其餘值則直接返回
  4. 返回值不能夠是null
function resolvePromise(promise2, x, resolve, reject) {
  // 只返回onresolve的第一個then 防止屢次調用
  let called;
  if(x === promise2 ){
    // reject報錯
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  // 若是是promise
  if (x !== null && (typeof x === "function" || typeof x === "object")) {
    try {
      // 若是onresolve返回值x是一個promise 則x存在then方法
      let then = x.then;
      if (typeof then === "function") {
        if (called) return;
        called = true;
        // 若是是promise 獲取promise.then 的返回值
        // 再執行一遍resolvePromise 拋出結果給下一個then
        /** * const a = new PromiseDemo((res,rej)=>{ res(222,'222') }) a.then.call(this,(a)=>{ console.log(a,'a') }) */
        then.call(
          x, // x是onReslove返回的 promise.then
          res => {
            // 獲取到onReslove 返回的promise.then的結果後調用resolvePromise 返回非promise的值
            resolvePromise(promise2, res, resolve, reject);
          },
          err => {
            reject(err);
          }
        );
      } else {
        resolve(x);
      }
    } catch (err) {
      if (called) return;
      called = true;
      reject(err);
    }
  } else {
    resolve(x);
  }
}


複製代碼

第五步: 思考驗證 —— 鏈式調用順序

我嘗試用下面的代碼驗證我寫的promise 鏈式調用順序 結果代碼報錯
這裏涉及到一個知識點 —— 鏈式調用順序promise

由於在同一個then內的回調callback都是被異步調用的, 因此同一級的then中先調用最外層then再向內層依次執行異步

  1. PENDING的時候 resolve和reject必須是異步調用
  2. resolve和reject若是是value的兼容
  3. 若是resolve或reject報錯,直接返回reject()
  4. 代碼任意地方異常則拋出error
new PromiseDemo((resolve, reject) => {
  console.log("log: 外部promise");
  resolve();
})
  .then(() => {
    console.log("log: 外部第一個then");
    new PromiseDemo((resolve, reject) => {
      console.log("log: 內部promise");
      resolve();
    })
      .then(() => {
        console.log("log: 內部第一個then");
      })
      .then(() => {
        console.log("log: 內部第二個then");
      });
  })
  .then(() => {
    console.log("log: 外部第二個then");
  });

// log: 外部promise
// log: 外部第一個then
// log: 內部promise
// log: 內部第一個then
// log: 外部第二個then
// log: 內部第二個then
複製代碼

下面是完整代碼async

const PENDING = "pending";
const FULFILLED = "fullilled";
const REJECTED = "rejected";

class PromiseDemo {
  constructor(executor) {
    this.state = PENDING;
    this.resolveResult = undefined;
    this.rejectResult = undefined;
    this.onResolve = undefined;
    this.onReject = undefined;
    let resolve = resolveResult => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.resolveResult = resolveResult;
        this.onResolve();
      }
    };
    let reject = rejectResult => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.rejectResult = rejectResult;
        this.onReject();
      }
    };
    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then = (onResolve, onReject) => {
    const promise2 = new PromiseDemo((resolve, reject) => {
      switch (this.state) {
        case PENDING:
            this.onResolve = () => {
              setTimeout(() => {
                try {
                  const fulfilledResult = onResolve(this.resolveResult);
                  resolvePromise(fulfilledResult, resolve, reject);
                } catch (err) {
                  reject(err);
                }
              }, 0);
            };
            this.onReject = () => {
              setTimeout(() => {
                try {
                  const rejectedResult = onReject(this.rejectResult);
                  resolvePromise(rejectedResult, resolve, reject);
                } catch (err) {
                  reject(err);
                }
              }, 0);
            };
            break;

            case FULFILLED:
                setTimeout(() => {
                  try {
                    const fulfilledResult = onResolve(this.resolveResult);
                    resolvePromise(promise2, fulfilledResult, resolve, reject);
                  } catch (err) {
                    reject(err);
                  }
                }, 0);
                break;
      

        default:
          setTimeout(() => {
            const rejectedResult = onReject(this.rejectResult);
            resolvePromise(promise2,rejectedResult, resolve, reject);
          }, 0)
          break;
      }
    });

    return promise2;
  };
  catch = onReject => {
    this.then(null, onReject);
  };
}

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    return reject(new TypeError("Chaining cycle detected for promise"));
  }
  let called;
  if (x != null && (typeof x === "object" || typeof x === "function")) {
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          err => {
            if (called) return;
            called = true;
            reject(err);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
複製代碼

第六步: promise實例 then的屢次調用 堆棧處理

promise的實例 在同一級別能夠調用多個then 因此咱們要把resolve回調用數組的形式儲存函數

const PENDING = "pending";
const FULFILLED = "fullilled";
const REJECTED = "rejected";

class PromiseDemo {
  constructor(executor) {
    this.state = PENDING;
    this.resolveResult = undefined;
    this.rejectResult = undefined;
    this.onResolve = [];
    this.onReject = [];
    let resolve = value => {
      if (this.state === PENDING) {
        this.state = FULFILLED;
        this.resolveResult = value;
        // 把resolve回調用數組的形式儲存
        this.onResolve.forEach(fn=>fn());
      }
    };
    let reject = reason => {
      if (this.state === PENDING) {
        this.state = REJECTED;
        this.rejectResult = reason;
        this.onReject.forEach(fn=>fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then = (onResolve, onReject) => {
    const promise2 = new PromiseDemo((resolve, reject) => {
      switch (this.state) {
        case PENDING:
        // 把resolve回調用數組的形式儲存
          this.onResolve.push(() => {
            setTimeout(() => {
              try {
                const fulfilledResult = onResolve(this.resolveResult);
                resolvePromise(fulfilledResult, resolve, reject);
              } catch (err) {
                reject(err);
              }
            }, 0);
          });
          this.onReject.push(() => {
            setTimeout(() => {
              try {
                const rejectedResult = onReject(this.rejectResult);
                resolvePromise(rejectedResult, resolve, reject);
              } catch (err) {
                reject(err);
              }
            }, 0);
          });
          break;

        case FULFILLED:
          setTimeout(() => {
            try {
              const fulfilledResult = onResolve(this.resolveResult);
              resolvePromise(promise2, fulfilledResult, resolve, reject);
            } catch (err) {
              reject(err);
            }
          }, 0);
          break;

        default:
          setTimeout(() => {
            const rejectedResult = onReject(this.rejectResult);
            resolvePromise(promise2, rejectedResult, resolve, reject);
          }, 0);
          break;
      }
    });

    return promise2;
  };
  catch = onReject => {
    this.then(null, onReject);
  };
}

function resolvePromise(promise2, x, resolve, reject) {
  if (x === promise2) {
    return reject(new TypeError("Chaining cycle detected for promise"));
  }
  let called;
  if (x != null && (typeof x === "object" || typeof x === "function")) {
    try {
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          y => {
            if (called) return;
            called = true;
            resolvePromise(promise2, y, resolve, reject);
          },
          err => {
            if (called) return;
            called = true;
            reject(err);
          }
        );
      } else {
        resolve(x);
      }
    } catch (e) {
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}

const p = new PromiseDemo((resolve, reject) => {
  setTimeout(() => {
    console.log("log: promise");
    resolve();
  }, 0);
});

p.then(() => {
  console.log("log: promise1");
});
p.then(() => {
  console.log("log: promise2");
});

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log("log: 真實promise");
    resolve();
  }, 0);
});

p2.then(() => {
  console.log("log: 真實promise1");
});
p2.then(() => {
  console.log("log: 真實promise2");
});

複製代碼

第七步: promise的其餘方法 —— promise完成

promise.all 等到全部結果返回 再調用resolvepost

PromiseDemo.all = (promises) =>{
  let results = [];
  function processResult (data,index,res) {
    results.push(data);
    if(promises.length === (index + 1)){
      res(results)
    }
  }
  return new Promise((res,rej)=>{
    try{
      promises.forEach((promise,index)=>{
        promise.then((result)=>{
          processResult(result,index,res)
        })
      })
    }catch(e){
      rej(e)
    }
  })
}
複製代碼

promise.race 等到第一個結果就調用resolve

PromiseDemo.race = (promises) =>{
  function processResult (data,res) {
    if(data){
      res(data)
    }
  }
  return new Promise((res,rej)=>{
    try{
      promises.forEach((promise)=>{
        promise.then((result)=>{
          processResult(result,res)
        })
      })
    }catch(e){
      rej(e)
    }
  })
}
複製代碼

async 函數的實現原理

阮一峯 es6裏就有講

async function fn(args) {
  
  // ...
}

// 等同於
function fn(args) {
  return spawn(function* () {
    // ...
  });
}
複製代碼
function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}
複製代碼
相關文章
相關標籤/搜索