【入門】promise的實現

promise javascript 異步

這幾天在看樸靈的深刻淺出nodejs,看到異步編程的解決方案這一章時,卡在了promise這個地方。心中的念頭就是本身動手寫一個promise纔好,因而就開始在網上找資料。javascript

簡介,這些代碼首先是發表在Stack Overflow,是但願你能從中學習如何使用javascript實現一個promise,你將會更好的理解promise是如何的實現的。html

狀態機

因爲promise僅僅是一個狀態機,咱們必須從咱們將會用到的狀態信息開始考慮。java

var PENDDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(){
    //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED
    var state = PENDDING;
    //一旦FULFILLED或者REJECTED保存爲value或者err
    var value = null;
    //保存成功或者失敗的處理程序
    var handlers = []
}

轉變

第二步,讓咱們考慮下面兩種可能出現的情形,fulfilling和rejecting:node

var PENDDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(){
    //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED
    var state = PENDDING;
    //一旦FULFILLED或者REJECTED保存爲value或者err
    var value = null;
    //保存成功或者失敗的處理程序
    var handlers = []

    function fullfill(result){
        state = FULFILLED;
        value = result;
    }

    function reject(error){
        state = REJECTED;
        value = error;
    }
}

上面這些給了咱們較低等級的變換,可是咱們還能夠考慮額外更高級的叫作resolve的變換。編程

var PENDDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(){
    //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED
    var state = PENDDING;
    //一旦FULFILLED或者REJECTED保存爲value或者err
    var value = null;
    //保存成功或者失敗的處理程序
    var handlers = []

    function fulfill(result){
        state = FULFILLED;
        value = result;    
    }

    function reject(error){
        state = REJECTED;
        value = error;
    }

    function resolve(result){
        try{
            var then = getThen(result);
            if(then){
                doResolve(then.resolve(result),resolve,reject)
                return 
            }
            fullfill(result)
        }catch(e){
            reject(e)
        }
    }
}

注意不管傳入resolve的是一個promise對象仍是一個普通值,若是它是一個promise對象,等待他完成。一個promise對象不會進入fulfilled狀態若是它還包含一個promise對象的話,所以咱們將要暴露出的resolve函數強於內部的fulfill。咱們用到了一系列的輔助函數,以下:promise

/**
 * 檢查一個value是不是一個promise對象,若是是,返回那個promise的then方法
 *
 * @param {promise|any} value
 * @return {Function|null}
 */
function getThen(value){
    var t = typeof value;
    if(value && (t === 'object'||t === 'function')){
        var then = value.then;
        if(typeof then === 'function'){
            return then
        }
    }
    return null
}
/**
 * 建立一個對潛在行爲的處理方法而且保證onFulfilled和onRejected只被調用一次
 * 不對異步作保證
 *
 * @param {Function} fn A resolver function that may not be trusted
 * @param {Function} onFulfilled
 * @param {Function} onRejected
 */
function doResolve(fn,onFulfilled,onRejected){
    var done = false;
    try{
        fn(function(value){
            if(done) return
            done = true
            onFulfilled(value)
        },function(reason){
            if(done) return 
            done = true
            onRejected(reason)
        })
    }catch(ex){
        if(done) return 
        done = true
        onRejected(ex)
    }
}

構造

咱們如今已經完成了內部的狀態機,但同時咱們還須要暴露一個處理或者觀察該promise的方法,咱們來增長一個處理promise的途徑:異步

var PENDDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn){
    //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED
    var state = PENDDING;
    //一旦FULFILLED或者REJECTED保存爲value或者err
    var value = null;
    //保存成功或者失敗的處理程序
    var handlers = []


    function fulfill(result){
        state = FULFILLED;
        value = result;    
    }

    function reject(error){
        state = REJECTED;
        value = error;
    }

    function resolve(result){
        try{
            var then = getThen(result);
            if(then){
                doResolve(then.resolve(result),resolve,reject)
                return 
            }
            fullfill(result)
        }catch(e){
            reject(e)
        }
    }

    doResolve(fn,resolve,reject)
}

如你所見,咱們複用了deResolve由於咱們有另外一個不被信任的處理器,fn函數能夠調用resolvereject屢次,甚至能夠拋出異常,咱們如今要作的是保證promise只執行或者拒絕一次,而後不在變換爲其餘的狀態。異步編程

觀察(.done方法)

咱們如今有一個已經完成的狀態機,可是咱們仍然沒有觀察他的變化。咱們最終要完成的是實現.then,可是因爲.done簡單不少因而咱們就先實現它。
咱們如今要實現promise.done(onFulfilled,onRejected)要知足如下的功能:
- onFulfilledonRejected中一個被調用
- 只被調用一次
- 在下一個tick(即.done方法返回後)時才被調用
- 它將會被調用無論promise是在咱們調用.done以前或者以後被處理函數

var PENDDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn){
    //保存的狀態能夠爲PENDDING,FULFILLED和REJECTED
    var state = PENDDING;
    //一旦FULFILLED或者REJECTED保存爲value或者err
    var value = null;
    //保存成功或者失敗的處理程序
    var handlers = []


    function fulfill(result){
        state = FULFILLED;
        value = result;
        handlers.forEach(handle);
        handlers = null
    }

    function reject(error){
        state = REJECTED;
        value = error;
        handlers.forEach(handle);
        handlers = null
    }

    function resolve(result){
        try{
            var then = getThen(result);
            if(then){
                doResolve(then.resolve(result),resolve,reject)
                return 
            }
            fullfill(result)
        }catch(e){
            reject(e)
        }
    }

    function handle(handler){
        if(state === PENDDING){
            handlers.push(handler)
        }else{
            if(state === FULFULLIED && typeof handler.onFulfilled === 'function'){
                handler.onFulfilled(value);
            }
            if(state === REJECTED && typeof handler.onRejected === 'function'){
                handler.onRejected(value);
            }
        }
    }

    this.done = function(onFulfilled,onRejected){
        //保證異步執行
        setTimeout(function(){
            handle({
                onFulfilled : onFulfilled,
                onRejected  : onRejected
            })
        },0)
    }

    doResolve(fn,resolve,reject)
}

咱們得肯定Promise被Resolved或者Rejected後處理程序能夠獲得通知,僅僅是在進入下一個tick時作這些。學習

觀察(.then方法)

如今咱們已經完成了.done方法,咱們能夠很相似的實現.then方法,只是要多構建一個Promise方法。

this.then = function(onFulfilled,onRejected){
    var self = this;
    return new Promise(function(resolve,Reject){
        return self.done(function(resolve){
                if(typeof onFulfilled === 'function'){
                    try{
                        resolve(onFulfilled(result))
                    }catch(e){
                        reject(e)
                    }
                }else{
                    return resolve(result)
                }
        },function(error){
            if(typeof onRejected === 'function'){
                try{
                    reject(onRejected(error))
                }catch(e){
                    reject(e)
                }
            }else{
                reject(error)
            }
        })
    })
}

以上翻譯自Promise Implementing

相關文章
相關標籤/搜索