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); });
  });
}
复制代码
相关文章
相关标签/搜索