隨便說說Promise

爲啥要說 promise ?javascript

由於這是前端必需要掌握的一個知識,吹逼必備前端

首先說說 Promise 是什麼?

Promise 是JavaScript的第一個異步標準模型,一個包含傳遞信息與狀態的對象,emmm...它的英語意思是承諾.
so 它擁有的特色也有承諾的意思(兄弟們,拿好筆記本,劃重點):java

  1. 對象的狀態不受外界影響,Promise 表示一個異步的操做,它有三個狀態 Pending (進行時)、Reslove (已完成)、Rejected (失敗),只有異步操做的結果,能夠決定當前是哪種狀態
  2. 一旦狀態改變就不會再接受改變,任什麼時候候均可以獲得這個結果。 Promise 對象的狀態改變,只有兩種可能,從 Pending 變爲 Resolved 或者 Rejected。 只要這兩種狀況發生,狀態就不會再改變了,就算狀態改變了,你再對 Promise 對象添加回調,也會當即獲得結果,這和事件 event 不一樣,事件的特色是一點你錯過了它,再去監聽也不會獲得結果的

那 Promise 爲何會出現呢?c++

Promise 以前的異步

Promise以前的時候,咱們用三個手段解決異步問題面試

  1. 回調函數
  2. 觀察者模式(又稱發佈訂閱模式)
  3. 事件機制

回調函數是最簡單的異步方式,它比較容易理解和部署,也是咱們最常使用的,可是缺點也很明顯,不利於代碼的閱讀和維護,流程混亂。數組

觀察者模式和事件機制很少說,就是適用於屢次同類型的異步,不適用一次性的異步promise

而 Promise 能夠將異步操做以同步操做的流程表達出來,併發

  1. 避免了層層回調函數。
  2. 若是使用回調函數, 你並不能知道對方是否執行你的回調函數,或太晚太早執行
  3. 錯誤也是異步,會隱式傳遞給reject

老哥,說了這麼多,怎麼用啊?

先來個最簡單的Prmise異步

const p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve('你好,兄弟') //設置成resolve狀態 便是成功
    },1e3)
})
p.then(res=>{
    console.log(res) // 1s後輸出 ==> 你好,兄弟
})

是否是看起來 so easy ?函數

下面咱們來實現一下最簡單的 Promise。 Promise只是一個普通的構造函數,用es3的語法也能夠實現
因此在ie6均可以用,不過咱們就使用class來實現了

class myPromise {
  constructor(fn) {
    this.state = 'PENDING';
    this.message = '';
    this.fns = [];
    fn(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(res) {
    this.state = 'FULFILLED';
    this.message = res;
    this._onChange();
  }
  reject(err) {
    this.state = 'REJECTED';
    this.message = err;
    this._onChange();
  }
  then(onResolved, onRejected) {
    let self = this;
    return new myPromise((resolve, reject) => {
      self.fns.push([onResolved, onRejected, resolve, reject]);
      self._onChange();
    });
  }
  _onChange() {
    this.state !== 'PENDING' &&
      this.fns.forEach(v => {
        this._change(v);
      });
  }
  _change(arr) {
    let onResolved = arr[0],
      onRejected = arr[1],
      resolve = arr[2],
      reject = arr[3];
    switch (this.state) {
      case 'FULFILLED':
        if (typeof onResolved === 'function') {
          resolve(onResolved.call(null, this.message));
        } else {
          resolve(this.message);
        }
        break;
      case 'REJECTED':
        if (typeof onRejected === 'function') {
          resolve(onRejected.call(null, this.message));
        } else {
          reject(this.message);
        }
        break;
      default:
        break;
    }
  }
}

//老哥們注意,這只是我本身寫的一個簡略的 Promise , 並非真正的 Promise 的實現

const p = new myPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('你好,兄弟'); //1s後設置成resolve狀態 便是成功
  }, 1e3);
});
p.then(res => {
  console.log(res); // 1s後輸出 ==> 你好,兄弟
  return '1';
})
  .then(res => {
    console.log(res); // 1s後輸出 ==> '1'
  })
  .then(res => {
    console.log(res); // 1s後輸出 ==> undefined
  });

Promise.resolve / reject

Promise 還提供一個快速實例化 Promise ,能夠傳入參數而且立刻觸發 Promise 鏈的執行

Promise.resolve = data =>
  new Promise((resolve, reject) => {
    resolve(data);
  });
Promise.reject = err =>
  new Promise((resolve, reject) => {
    reject(err);
  });

Promise.all / race

Promise 還提供 all / race 用來處理數據的併發和競爭,要求是傳一個 Promise 數組做爲參數,而後返回一個新的 Promise

all 是所有處理後再統一處理

Promise.all = arr =>
  new Promise((resolve, reject) => {
    let c = 0,
      l = arr.length,
      result = [];
    l === 0 && resolve(result);
    arr.forEach(pro => {
      Promise.resolve(pro).then(res => {
        result.push(res);
        c++;
        c === l && resolve(result);
      },
        err => {
          reject(err);
        }
      );
    });
  });

race 則是誰異步時間短誰就會被處理

Promise.race = arr =>
  new Promise((resolve, reject) => {
    arr.forEach(pro => {
      Promise.resolve(pro).then(resolve, reject);
    });
  });

Promise.then / catch

Promise 的 then 函數咱們也知道是怎麼用的,它始終以當前的結果返回一個新的Promise
而以前咱們說到 Promise 的錯誤是異步的 也直接調用到 reject,
那咱們在 resolve 或者 reject 出現錯誤應該怎麼作呢? Promise 還提供一個catch 用來捕捉錯誤

Promise.catch = reject => this.then(undefined,reject)

怎麼用呢?

const p = new Promise((resolve, reject) => {
  //執行操做
  //..略
});

p.then(resolve, reject)
  .then(resolve, reject)
  .then(resolve, reject)
  .catch(err => {
    //若是以上出現錯誤會直接傳遞到此處執行錯誤處理
  });

Promise 和 setTimeout

說是異步,那麼和咱們最原始的 setTimeout 有什麼區別呢?
先讓咱們看一道面試題目

console.log('a');

setTimeout(() => {
  console.log('b');
});

console.log('c');

new Promise((resolve, reject) => {
  console.log('d');
  resolve('e');
}).then(res => {
  console.log(res);
});

console.log('f');

輸出順序是什麼呢 ?

a => c => d => f => e => b

這裏就要關係到js的 EventLoop 機制了,這裏並不細說,只是拋個引子,有興趣的朋友能夠去看看相關文章

結尾

到這裏就結束了,老哥們,要去搬磚了

若是發現文章有什麼問題,能夠留言哦

相關文章
相關標籤/搜索