勇敢猿猿,不怕困难-----手写Promise(上)

261 阅读4分钟

前言

Promis方面的知识点一直都是前端面试的重点和难点,手写Promise更是对前端工程师的一大挑战。今天来写并讲一下一个通俗易懂的版本。话不多说,勇敢猿猿,不怕困难!!!!

先来点简单的

  1. 先写一个自执行函数,然后把自己写的Promise函数暴露出去,这样window中的Promise就是我们写的Promise。大家都知道,在创建Promise实例的时候,必须传进去一个函数,否则会报错,所以在函数里第一步就是判断传进拉的exeutor参数是否是函数,如果不是函数就抛出该错误。
 (function () {
	function Promise(executor) { 
	 //实例化promise的时候没有传参数,保证executor必须是一个函数
          if (typeof executor !== 'function') {
            throw new TypeError('Promise resolver' + executor + 'is not a function ');
          }
	}
	// 将自己写的promise暴露出去
	 window.Promise = Promise;
 })();
 let p1 = new Promise((resolve, reject) => {});
  1. 然后传进来的executor函数会立即执行,并且executor函数有两个参数函数,分别是resolve和reject,这连个函数参数分别可以改变Promise实例的结果(PromiseResult )和状态(PromiseState )。Promise有三种状态,成功态(fulfilled),失败态(rejected),等待态(pending)。刚开始Promise都是等待态。
(function () {
	function Promise(executor) { 
	 //实例化promise的时候没有传参数,保证executor必须是一个函数
          if (typeof executor !== 'function') {
            throw new TypeError('Promise resolver' + executor + 'is not a function ');
          }
          //self:存储的是promise实例
          var self = this;
          self.PromiseState = 'pending';
          self.PromiseResult = undefined;
          executor(resolve, reject);
	}
	// 将自己写的promise暴露出去
	 window.Promise = Promise;
 })();
 let p1 = new Promise((resolve, reject) => {
	 resolve('ok')
});
  1. resolve函数是将Promise实例由等待态变为成功态,reject函数是将Promise由等待态变为失败态;并将传进resolve函数和reject函数的参数赋给Promise实例的结果(PromiseResult)。但是别忘了,成功态和失败态不能互相转化,所以要函数执行后第一件事是判断当前的Promise实例是否是等待态。 3.1 还有一点特别注意,如果executor函数报错,那么Promise实例也会进入失败态,那么就用try catch来捕获executor函数的报错,让其报错时,执行reject函数。
(function () {
	function Promise(executor) { 
	 //实例化promise的时候没有传参数,保证executor必须是一个函数
          if (typeof executor !== 'function') {
            throw new TypeError('Promise resolver' + executor + 'is not a function ');
          }
          //self:存储的是promise实例
          var self = this;
          self.PromiseState = 'pending';
          self.PromiseResult = undefined;
          var resolve=function resolve(value){
          	if (self.PromiseState === 'pending') {
				self.PromiseState = 'fulfilled';
              	self.PromiseResult = value;
			}
          }
          var reject=function resolve(reason){
          	if (self.PromiseState === 'pending') {
              self.PromiseState = 'rejected';
              self.PromiseResult = reason;
            }
          }
          try {
            executor(resolve, reject);
          } catch (error) {
            reject(err);
          }
	}
	// 将自己写的promise暴露出去
	 window.Promise = Promise;
 })();
 let p1 = new Promise((resolve, reject) => {
	 resolve('ok')
});

坚持住!!往下看

  1. Promise实例有.then方法和.catch方法来处理实例在成功态和失败态时对后续代码的处理,那我们把这些写到Promise的原型上 4.1 下面写原型的方式,别忘了把constructor(构造函数指回Promise)
  2. 首先 .then方法有两种情况,一种是知道立即知道Promise实例的情况,就比如在executor函数里同步执行代码,立刻可以知道实例是成功态还是失败态,这样就可以通过实例的PromiseState做出判断,调用哪个函数;另一种是不能立即知道实例的状态,就比如executor函数中执行了一个1s的定时器,不能马上得出实例的状态,这时我们应该把执行的函数存起来,执行resolve/reject函数时,通知其执行。
  3. 其次,.then方法是异步的执行的,所以不管是成功还是失败的处理函数,放在定时器里执行。
 function Promise(executor) {
 .....
  self.onFulfilledCallbacks = [];
  self.onRejectedCallbacks = [];
 .....
}
 Promise.prototype = {
	 constructor: Promise,
	 then: function (onfulfilled, onrejected) {
	 	var self = this;
        switch (self.PromiseState) {
          //知道状态的情况
           case 'fullfilled':
               setTimeout(function () {
                 onfulfilled(self.PromiseResult);
              	});
               break;
           case 'rejected':
              setTimeout(function () {
                 onrejected(self.PromiseResult);
               });
               break;
           //不知道状态的情况
           default:
                self.onFulfilledCallbacks.push(onfulfilled);
                self.onRejectedCallbacks.push(onrejected);
                break;
         }
	 }
	 
}
  1. 执行resolve/reject,立即更改状态信息,但不会立即通知方法执行(异步效果),onFulfilledCallbacks中保存着成功时的处理函数,onRejectedCallbacks中保存这失败时的处理函数,等executor函数中的异步函数执行完,resolve/reject执行时遍历这个两个数组,修改Promise实例的结果。
function resolve(value) {
	if (self.PromiseState === 'pending') {
		....
		setTimeout(function () {
                for (var i = 0; i < self.onFulfilledCallbacks.length; i++) {
                  let itemFunc = self.onFulfilledCallbacks[i];
                  if (typeof itemFunc === 'function') {
                    itemFunc(self.PromiseResult);
                  }
                }
        });
	}
}
function reject(reason) {
	if (self.PromiseState === 'pending') {
		....
		setTimeout(function () {
                for (var i = 0; i < self.onRejectedCallbacks.length; i++) {
                  let itemFunc = self.onRejectedCallbacks[i];
                  if (typeof itemFunc === 'function') {
                    itemFunc(self.PromiseResult);
                  }
                }
        });
	}
}
  1. 到这点,面试时写到这点基本就可以了,Promise基本的特点基本完成了;Promise函数立即执行,resolve/reject/.then这样函数异步执行,只能有等待态转为成功态或者失败态。是不是很简单....