來實現一個簡易版的 Promise

前言

Promise 是 JavaScript 中用於異步操做很是重要的一個構造函數,那麼它是怎麼實現的呢?promise

下面用原生 JavaScript 來實現一個簡易版的 Promise,用來實現如下代碼。異步

function Promise(???){
    ???
    return ???
}

var promise = new Promise(function(resolve, reject) {
  setTimeout(() => {
    resolve('hello');
  }, 3000);
});

promise.then(
  val => {
    console.log('第一次成功', val);// 輸出 第一次成功 hello
  },
  val => {
    console.log('第一次失敗', val);
  }
);
複製代碼

實現

用過 Promise 的朋友都知道,Promise 要接受一個函數 fn 並調用它,Promise 還應該有一個表示狀態( pending, resolved, rejected )的屬性值 status,一個 value 存儲 then 回調時傳的值,還有一個 then 方法。其餘方法暫時不考慮了。函數

function Promise(fn) {
  //初始 status 爲 peding
  let status = 'pending';
  //存儲 then 回調值
  let value;
  //存儲 then 的兩個參數
  let onResolvedCallback;
  let onRejectedCallback;

  //設置 fn 的 resolve 函數
  function resolve(data) {
    //將 status 變成 fulfilled
    status = 'fulfilled';
    //存儲回調函數的值
    value = data;
    toDoThen(onResolvedCallback, onRejectedCallback);
  }

  //設置 fn 的 reject 函數
  function reject(data) {
    //將 status 變成 rejected
    status = 'rejected';
    //存儲回調函數的值
    value = data;
    toDoThen(onResolvedCallback, onRejectedCallback);
  }

  //設置 resolve 或 reject 時的執行體
  function toDoThen(onFulfill, onReject) {
    //若是是 fulfilled 狀態,表示要執行 then 的第一個函數
    if (status === 'fulfilled') {
      onFulfill && onFulfill(value);
      status = 'pending';
    //若是是 rejected 狀態,表示要執行 then 的第二個函數
    } else if (status === 'rejected') {
      onReject && onReject(value);
      status = 'pending';
    //若是狀態仍是 peding,表示 resolve 或 reject 還沒執行,那就先把 then 的兩個函數存起來,等 resolve 或 reject 的時候再調用
    } else {
      onResolvedCallback = onFulfill;
      onRejectedCallback = onReject;
    }
  }

  //將 then 獲得的函數傳給 toDoThen
  this.then = function(onFulfill, onReject) {
    toDoThen(onFulfill, onReject);
  };

  //執行 fn
  fn(resolve, reject);

  return this;
}
複製代碼

測試一波測試

var promise = new Promise(function(resolve, reject) {
  setTimeout(() => {
    resolve('hello');
  }, 3000);
});

promise.then(
  val => {
    console.log('第一次成功', val);
  },
  val => {
    console.log('第一次失敗', val);
  }
);
複製代碼

執行時會打印出 '第一次成功' 和 'hello'ui

鏈式 then

若是想要實現如下的代碼,讓第二個 then 的執行函數是根據第一個 then 返回值的布爾值來肯定的。this

promise
  .then(
    val => {
      console.log('第一次成功', val);
      return 'world';
    },
    val => {
      console.log('第一次失敗', val);
      return false;
    }
  )
  .then(
    val => {
      console.log('第二次成功', val);
    },
    val => {
      console.log('第二次失敗', val);
    }
  );
複製代碼

這裏若是要實現鏈式 then,那麼 then 返回的也必須是一個 Promise 對象,並根據第一個 then 的返回值來肯定下一個 then 調用哪一個函數。spa

function Promise(fn) {
  //初始 status 爲 peding
  let status = 'pending';
  //存儲 then 回調值
  let value;
  //存儲 then 的兩個參數
  let onResolvedCallback;
  let onRejectedCallback;

  //設置 fn 的 resolve 函數
  function resolve(data) {
    //將 status 變成 fulfilled
    status = 'fulfilled';
    //存儲回調函數的值
    value = data;
    toDoThen(onResolvedCallback, onRejectedCallback);
  }

  //設置 fn 的 reject 函數
  function reject(data) {
    //將 status 變成 rejected
    status = 'rejected';
    //存儲回調函數的值
    value = data;
    toDoThen(onResolvedCallback, onRejectedCallback);
  }

  //設置 resolve 或 reject 時的執行體
  function toDoThen(onFulfill, onReject) {
    //若是是 fulfilled 狀態,表示要執行 then 的第一個函數
    if (status === 'fulfilled') {
      onFulfill && onFulfill(value);
      status = 'pending';
    //若是是 rejected 狀態,表示要執行 then 的第二個函數
    } else if (status === 'rejected') {
      onReject && onReject(value);
      status = 'pending';
    //若是狀態仍是 peding,表示 resolve 或 reject 還沒執行,那就先把 then 的兩個函數存起來,等 resolve 或 reject 的時候再調用
    } else {
      onResolvedCallback = onFulfill;
      onRejectedCallback = onReject;
    }
  }

  this.then = function(onFulfill, onReject) {
    return new Promise((resolve, reject) => {
      toDoThen(
        val => {
          let result = onFulfill(val);
          //根據第一個 then 的返回值來肯定下一個 then 的調用
          result ? resolve(result) : reject(result);
        },
        err => {
          let result = onReject(err);
          //根據第一個 then 的返回值來肯定下一個 then 的調用
          result ? resolve(result) : reject(result);
        }
      );
    });
  };

  //執行 fn
  fn(resolve, reject);

  return this;
}
複製代碼

來執行一下code

var promise = new Promise(function(resolve, reject) {
  setTimeout(() => {
    resolve('hello');
  }, 3000);
});

promise
  .then(
    val => {
      console.log('第一次成功', val);
      return 'world';
    },
    val => {
      console.log('第一次失敗', val);
      return false;
    }
  )
  .then(
    val => {
      console.log('第二次成功', val);
    },
    val => {
      console.log('第二次失敗', val);
    }
  )
複製代碼

程序會依次輸出 '第一次成功' 'hello' 和 '第二次成功' 'world' 。對象

到此就實現了一個簡易版的 Promise,固然,還有不少地方細節沒有考慮到,實現地很是粗糙。ip

相關文章
相關標籤/搜索