promise理解與實現

Meteor發表於2018-01-15

promise理解

promise的意思是承諾。承諾理解為某個時候一些條件滿足後,會兌現一件事情。

//為了方便理解我編一個小故事
//先假裝我有一個女朋友
//她承諾如果她爸媽不回來就給我就可以去幫她修電腦 否則...
let promise = new Promise(function (success,fail) {
    //她說三秒後會告訴我今晚爸媽回不回來
    let herParentBack = Math.random() > 0.5 ? true : false;
    setTimeout(function(){
        if(herParentBack){
            success('我馬上過來來幫你修你電腦');
        }else{
            fail('你要早點休息');
        }
    },3000);

});
 
 //第一個函式接收sucess函式傳來的成功資訊
 //第二個函式接收fail函式傳來的失敗資訊

promise.then(function (sucessMsg) {
    console.log(sucessMsg);
},function (fail) {
    console.log(failMsg);
})
//我馬上過來幫你修電腦
複製程式碼

new Promise會傳入一個回撥函式,會伴著物件建立被立即呼叫。 這個function是承諾的主體內容。一般我們會做一些判斷或者非同步請求。(在這裡要等女友回訊息,我想好怎麼回答她。)

promise.then方法在promise執行了success或fail後會執行對應的成功失敗方法。 (這裡理解為吧想好告訴她)

promise實現

根據promis規範promise Promise/A

Promise設定了三個狀態,'pending'、'resolved'、'rejected'。

//Promise物件設定初始狀態
function Promise(callback) {
    var self = this;
    //預設為等待狀態
    self.status = 'pending';
    self.value = undefined;
    self.reason = undefined;
    //用陣列來儲存成功函式
    self.onResolvedCallBacks = [];
    self.onRejectedCallbacks = [];

    function resolve(value){
        if(self.status === 'pending'){
            //設定為成功狀態
            self.status = 'resolved';
            self.value = value;
            self.onResolvedCallBacks.forEach(item=>item(self.value));
        }
    }
    function reject(reason) {
        if(self.status === 'pending'){
            //設定為失敗狀態
            self.status = 'rejected';
            self.reason = reason;
            self.onRejectedCallbacks.forEach(item=>item(self.reason));
        }
    }

    callback(resolve,reject);
    //呼叫Promise回撥函式
}

module.exports = Promise;
複製程式碼

增加Promise.then方法

//根據Promise狀態執行成功失敗方法
Promise.prototype.then = function (onFulfilled,onRejected) {
    let self = this;
    onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return value};
  onReject = typeof onReject=='function'?onReject:function(reason){throw reason;}
    if(self.status === 'resolved'){
        return new Promise(function (resolve,reject) {
            try {
                let x = onFullFilled(self.value);
                if(x instanceof Promise){
                    x.then(resolve,reject);
                }else{
                    resolve(x);
                }
            }
            catch(e) {
                reject(e);
            }
        })
        //執行成功方法
    }else if(self.status == 'rejected'){
        return new Promise(function (resolve,reject) {
            try {
                let x = onRejected(self.reason);
                if(x instanceof Promise){
                    x.then(resolve,reject);
                }else{
                    resolve(x);
                }
            }
            catch(e) {
                reject(e)
            }
        })
        //執行失敗方法
    }
    if(self.status === 'pending'){
        return new Promise(function (reslove,reject) {
            self.onResolvedCallBacks.push(function () {
                let x = onFullFilled(self.value);
                if(x instanceof Promise){
                    x.then(resolve,reject);
                }else{
                    resolve(x);
                }
            })
            self.onRejectedCallbacks.push(function () {
                let x = onRejected(self.reason);
                if(x instanceof Promise){
                    x.then(resolve,reject);
                }else{
                    resolve(x);
                }
            })
        })
        //將成功失敗方法儲存在陣列裡
    }
}
複製程式碼

Promise.all

Promise.all = all;
function all(iterable) {
  var self = this;
  if (!isArray(iterable)) {
    return this.reject(new TypeError('must be an array'));
  }

  var len = iterable.length;
  var called = false;
  if (!len) {
    return this.resolve([]);
  }

  var values = new Array(len);
  var resolved = 0;
  var i = -1;
  var promise = new this(INTERNAL);

  while (++i < len) {
    allResolver(iterable[i], i);
  }
  return promise;
  function allResolver(value, i) {
    self.resolve(value).then(resolveFromAll, function (error) {
      if (!called) {
        called = true;
        doReject(promise, error);
      }
    });
    function resolveFromAll(outValue) {
      values[i] = outValue;
      if (++resolved === len && !called) {
        called = true;
        doResolve(promise, values);
      }
    }
  }
}
複製程式碼

Promise.then

Promise.race = function(iterable) {
  var self = this;
  if (!isArray(iterable)) {
    return this.reject(new TypeError('must be an array'));
  }

  var len = iterable.length;
  var called = false;
  if (!len) {
    return this.resolve([]);
  }

  var i = -1;
  var promise = new this(INTERNAL);

  while (++i < len) {
    resolver(iterable[i]);
  }
  return promise;
  function resolver(value) {
    self.resolve(value).then(function (response) {
      if (!called) {
        called = true;
        doResolve(promise, response);
      }
    }, function (error) {
      if (!called) {
        called = true;
        doReject(promise, error);
      }
    });
  }
}
複製程式碼

相關文章