步步为营,手写promise

196 阅读5分钟

手写promise,重点理清思路,步步为营。以下,请实操!

声明一个叫promise类,难度1颗星

已知:promise是个类,其参数是一个函数,专业名词是executor,executor立即执行

实战,自己来个promise类让hi成功打印!

let p = new Promise(() => {
    // 就这行执行
    console.log('hi')
});
console.log(p);

答案的分割线,hi!,这个难住的话,就不用往下看了,ha sa ki !!!

揭晓答案:

class Promise {
  constructor(executor) {
    executor();
  }
}

加入resolve和reject,难度2颗星

再已知:executor里面有两个参数,一个叫resolve,一个叫reject。因为使用的时候,直接用,所以内部必然已经定义了resolve和reject,再传入到executor。

实战:让resolve或者reject能执行!

let p = new Promise((resolve, reject) => {
  if (Math.random() > 0.5) {
    //   这个执行
    resolve();
  } else {
    //   或这个执行
    reject();
  }
});
console.log(p);

答案的分割线,hi!,这个难住的话,看了下面 再想想 !!!

揭晓答案:

class Promise {
  constructor(executor) {
    const resolve = () => {
      console.log(1);
    };
    const reject = () => {
      console.log(0);
    };
    executor(resolve, reject);
  }
}

let p = new Promise((resolve, reject) => {
  if (Math.random() > 0.5) {
    resolve();
  } else {
    reject();
  }
});
console.log(p);

加入状态,难度3颗星

再已知:

  • promise有 状态 和 value或reason,初始状态是pending,初始的value和reason都是undefined
  • promise一共三种状态:pending/fulfilled/rejected
  • 初始状态是pending,随着程序的运行,其可以转变为fulfilled 或 rejected,但只能转变一次
  • fulfilled的时候,状态不能再改变,且必须有一个不可改变的值(value),可以是undefined
  • rejected的时候,状态不能再改变,且必须有一个不可改变的原因(reason),可以是undefined
  • resolve函数可以将promise的state变成fulfilled,value任意传入的
  • reject函数可以将promise的state变成rejected,reason任意传入的
  • 若executor函数报错,直接执行reject()
  • 这里反向推导,想要状态变化必须执行resolve或者reject

实战:让p是个有状态有值的!不是pending的那种!


let p = new Promise((resolve, reject) => {
  // 如果这里报错直接变成rejected,reason就是e
  // console(1);
  if (Math.random() > 0.5) {
    resolve(1);
    // 状态已定,这里其实永远不会执行
    console(1);
  } else {
    reject(0);
  }
  //  状态已定,这里其实永远不会执行
  resolve(2);
});
// !!!让p必须有最终的状态和value/reason
console.log(p);

答案的分割线,hi!,这个难住的话,看了下面 再想想 !!!

揭晓答案:

class Promise {
  constructor(executor) {
    // 定义三种状态
    const PENDING = "pending";
    const FULFILLED = "fulfilled";
    const REJECTED = "rejected";

    const resolve = value => {
      // 状态已定,就不做操作了
      if (this.state !== PENDING) {
        return;
      }
      // promise的值和状态
      this.value = value;
      this.state = FULFILLED;
      console.log(value);
    };
    const reject = reason => {
      // 状态已定,就不做操作了
      if (this.state !== PENDING) {
        return;
      }
      // promise的reason和状态
      this.reason = reason;
      this.state = REJECTED;
      console.log(reason);
    };
    // 定义 初始状态/value/reason
    this.state = PENDING;
    this.value = undefined;
    this.reason = undefined;
    // 注意executor执行的时候,若报错,则直接reject
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
}

let p = new Promise((resolve, reject) => {
  // 如果这里报错直接变成rejected,reason就是e
  // console(1);
  if (Math.random() > 0.5) {
    resolve(1);
    // 状态已定,这里其实永远不会执行
    console(1);
  } else {
    reject(0);
  }
  //  状态已定,这里其实永远不会执行
  resolve(2);
});
console.log(p);

加入then,难度2颗星

再已知:

  • Promise有一个叫做then的方法,里面有两个参数:onFulfilled,onRejected
  • 当promise的状态是fulfilled,则执行onFulfilled,传入this.value。为rejected的时候,则执行onRejected,传入this.reason

实战:让log打印出来then和value


let p = new Promise((resolve, reject) => {
  if (Math.random() > 0.5) {
    resolve(1);
  } else {
    reject(0);
  }
});
p.then(
  value => {
    // 让这行执行
    console.log("then", value);
  },
  reason => {
    // 或让这行执行
    console.log("then", reason);
  }
);
console.log(p);

答案的分割线,hi!,这个难住的话,看了下面 再想想 !!!

揭晓答案:

// 定义三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise {
  constructor(executor) {
    const resolve = value => {
      // 状态已定,就不做操作了
      if (this.state !== PENDING) {
        return;
      }
      // promise的值和状态
      this.value = value;
      this.state = FULFILLED;
    };
    const reject = reason => {
      // 状态已定,就不做操作了
      if (this.state !== PENDING) {
        return;
      }
      // promise的reason和状态
      this.reason = reason;
      this.state = REJECTED;
    };
    // 定义 初始状态/value/reason
    this.state = PENDING;
    this.value = undefined;
    this.reason = undefined;
    // 注意executor执行的时候,若报错,则直接reject
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    if (this.state === FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.state === REJECTED) {
      onRejected(this.reason);
    }
  }
}

加入异步的处理,难度3颗星

其实到这里,如果promise中没有异步的操作,那上面就够用了。 然而!!!promise就是为了解决异步而存在的。。。。。

也就是加个setTimeout,一切就归零了,这里then那边不会执行,因为还是pending呢。

继续,再已知:

  • 这里加个观察者模式。
  • then的时候,将onFulfilled或onRejected加入到观察者队列。
  • 状态变化的时候,也就是执行resolve或reject的时候,让相应的观察者做出行动。

实战:来!再让log打印出来then和value,你可以!来战!


let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve(1);
    } else {
      reject(0);
    }
  }, 200);
});
p.then(
  value => {
    // 对,让这行执行
    console.log("then", value);
  },
  reason => {
    // 或者这行
    console.log("then", reason);
  }
);
console.log(p);

答案的分割线,hi!,这个难住的话,看了下面 再想想 !!!

揭晓答案:

// 定义三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise {
  constructor(executor) {
    const resolve = value => {
      // 状态已定,就不做操作了
      if (this.state !== PENDING) {
        return;
      }
      // promise的值和状态
      this.value = value;
      this.state = FULFILLED;
      // 状态变化,触发观察者行动
      this.onFulfilledCallbacks.forEach(fn => {
        fn(this.value);
      });
    };
    const reject = reason => {
      // 状态已定,就不做操作了
      if (this.state !== PENDING) {
        return;
      }
      // promise的reason和状态
      this.reason = reason;
      this.state = REJECTED;
      // 状态变化,触发观察者行动
      this.onRejectedCallbacks.forEach(fn => {
        fn(this.reason);
      });
    };
    // 定义 初始状态/value/reason
    this.state = PENDING;
    this.value = undefined;
    this.reason = undefined;
    // 异步的话,就用到观察者模式,先存起来,遇到情况再执行
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];
    // 注意executor执行的时候,若报错,则直接reject
    try {
      executor(resolve, reject);
    } catch (e) {
      reject(e);
    }
  }
  then(onFulfilled, onRejected) {
    if (this.state === FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.state === REJECTED) {
      onRejected(this.reason);
    }
    // 如果是pending,那就说明有异步,加入到观察者队列!
    if (this.state === PENDING) {
      this.onFulfilledCallbacks.push(onFulfilled);
      this.onRejectedCallbacks.push(onRejected);
    }
  }
}

let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve(1);
    } else {
      reject(0);
    }
  }, 200);
});
p.then(
  value => {
    console.log("then", value);
  },
  reason => {
    console.log("then", reason);
  }
);
console.log(p);

加入链式的处理,难度5颗星

我还不会!哈哈哈!回头会了补上!

BAT前端经典面试问题:史上最最最详细的手写Promise教程