Promise的使用及簡單實現

張文夢發表於2018-05-29

一. promise是什麼

簡單來說是一種非同步流程的控制手段

  • 所謂Promise ,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說,Promise是一個物件,從它可以獲取非同步操作的訊息。Promise 物件的狀態不受外界影響

  • 在JavaScript的世界中,所有程式碼都是單執行緒執行的。 由於這個“缺陷”,導致JavaScript的所有網路操作,瀏覽器事件,都必須是非同步執行。

    非同步執行容易造成回撥地獄

    例如:

    $.ajax(
        success(){
            $.ajax(
                success(){
                    
                }
            )
        }
    )
    複製程式碼

    使用promise的鏈式呼叫就可以很好的解決這個問題

    例如:vue-resource

    this.$http.post(url,parms).then(res => {
        console.log(res)
    },err => {
        
    }).then(res=>{
        
    },err=>{
        
    })
    複製程式碼

二.promise的使用及方法

ES6規定,Promise物件是一個建構函式,用來生成Promise例項。Promise本身有all、race、reject、resolve這幾個方法

  • Promise只有一個引數 叫excutor執行器,預設new時就會呼叫
    let p = new Promise((resolve,reject)=>{ 
      // 預設promise中的executor是同步執行的
       resolve('買');
    });
    // then方法是非同步呼叫的,事件環
    p.then((value)=>{ // value成功的原因
      console.log(value);//買
    },(err)=>{ // err失敗的原因
    });
    複製程式碼

注意:then方法是Promise例項上的方法

  • Promise的reject、resolve方法

    promise有三種狀態:resolve 成功 reject 失敗 pending 等待態。 如果一旦promise成功了就不能失敗,相反也是一樣的,只有狀態是等待的狀態時才可以轉化狀態。pending->reject(resolve)

    Promise的使用及簡單實現

    1.Promise.resolve() 返回一個成功的promise

    2.Promise.reject() 返回一個失敗的promise

    例:

    
    let fs = require('fs'); // fileSystem
    function read(url) {
      return new Promise((resolve, reject) => {
        fs.readFile(url, 'utf8', function (err, data) {
          if (err) reject(err);//成功返回
          resolve(data);//失敗返回
        })
      })
    }
    
    複製程式碼
  • Promise的all、race方法

    promise可以支援多個併發的請求,獲取併發請求中的資料

    1.Promise.all

    這可能是個很有用的方法,它可以統一處理多個Promise。Promise.all能將多個Promise例項包裝成一個Promse例項

        let Promise1 = new Promise(function(resolve, reject){})
        let Promise2 = new Promise(function(resolve, reject){})
        let Promise3 = new Promise(function(resolve, reject){})
        
        let p = Promise.all([Promise1, Promise2, Promise3])
        
        p.then(funciton(){
          // 三個都成功則成功  
        }, function(){
          // 只要有失敗,則失敗 
        })
    
    複製程式碼

    2.Promise.race()

    與all方法類似,也可以將多個Promise例項包裝成一個新的Promise例項 不同的是,all時大Promise的狀態由多個小Promise共同決定,而race時由第一個轉變狀態的小Promise的狀態決定,第一個是成功態,則轉成功態,第一個失敗態,則轉失敗態。

    ** 簡單來說就是賽跑,處理多請求只取最快的 **

    let fs = require('fs'); // fileSystem
    function read(url) {
      return new Promise((resolve, reject) => {
        fs.readFile(url, 'utf8', function (err, data) {
          if (err) reject(err);//成功返回
          resolve(data);//失敗返回
        })
      })
    }
    Promise.race([read('1.txt'),read('2.txt')]).then((data)=>{
      console.log(data);//最快讀取完成功則成功
    },err=>{
      console.log(err);//最快讀取完失敗則失敗
    });
    
    複製程式碼

三. promise的簡單實現

通過上文我們已經知道Promise是一個建構函式,我們可以使用ES6的class類來建立一個Promise

下面我們建立一個class類來完成promise的then、reject、resolve方法

class Promise {
   constructor(executor) {
     // 預設狀態是等待態
     this.status = 'pending';
     this.value = undefined;
     this.reason = undefined;
     // 存放成功的回撥
     this.onResolvedCallbacks = [];
     // 存放失敗的回撥
     this.onRejectedCallbacks = [];
     let resolve = (data) => {
       if (this.status === 'pending') {
         this.value = data;
         this.status = 'resolved';
         this.onResolvedCallbacks.forEach(fn => fn());
       }
     }
     let reject = (reason) => {
       if (this.status === 'pending') {
         this.reason = reason;
         this.status = 'rejected';
         this.onRejectedCallbacks.forEach(fn => fn());
       }
     }
     try { // 執行時可能會發生異常
       executor(resolve, reject);
     } catch (e) {
       reject(e); // promise失敗了
     }
   }
   then(onFulFilled, onRejected) {
     if (this.status === 'resolved') {
       onFulFilled(this.value);
     }
     if (this.status === 'rejected') {
       onRejected(this.reason);
     }
     // 當前既沒有完成 也沒有失敗
     if (this.status === 'pending') {
       // 存放成功的回撥
       this.onResolvedCallbacks.push(() => {
         onFulFilled(this.value);
       });
       // 存放失敗的回撥
       this.onRejectedCallbacks.push(() => {
         onRejected(this.reason);
       });
     }
   }
 }
 module.exports = Promise;
 
複製程式碼

完成了基本的功能,我們可以使用自己寫的promise來測試一下


 let Promise = require('./promise');//引入
 let p = new Promise((resolve,reject)=>{
   resolve(123);
   reject(123);
 });
 p.then((data)=>{
   console.log('s',data);//s,123
 },(err)=>{
   console.log('e',err);//e,123
 });
 
複製程式碼

總結:

  • Promise是一種非同步流程的控制手段

  • 每一個promise的例項上都有一個then方法,then方法中有兩個引數,一個引數叫成功的函式 ,一個是失敗的函式

  • Promise可以鏈式呼叫,並且可以支援多個併發的請求,獲取併發請求中的資料

  • 如果一旦promise成功了就不能失敗,相反也是一樣的。只有狀態是等待的狀態時 才可以轉化狀態

  • Promise可以解決非同步的問題,但不能說promise本身是非同步的

相關文章