實現簡易 ES6 Promise 功能 (二)

上一篇文章【實現簡易 ES6 Promise 功能 (一)】實現了基本的異步功能。今天咱們接着上次的內容繼續扯,如何實現【數據傳遞】以及當【回調函數返回一個新的promise】segmentfault

上篇已完成的代碼數組

function Promise(func){
    this.state = 'pending';
    this.doneList = []; 
    func(this.resolve.bind(this)); 
}

Promise.prototype = {
    
    resolve: function(){
        while(true){
            if( this.doneList.length === 0 ){
                this.state = 'done';
                break;
            }
            this.doneList.shift().apply(this);
        }
    },
    
    then: function(callback){ 
        this.doneList.push(callback); 
        if( this.state === 'done'){
            this.state = 'pending';
            this.resolve();
        }
        return this; 
    }
}

測試代碼promise

new Promise(function(resolve){
    resolve(1)
}).then(function(data){
    console.log(data); // 1
    return 2;
}).then(function(data){
    console.log(data); // 2
});

上面的結果,就是咱們要實現的。resolve的參數(只傳遞第一個參數,若是有)傳遞給第一個then裏面函數做爲參數,第一個then裏面的函數返回值傳遞給第二個then裏面的函數做爲參數,以此類推。app

關鍵代碼異步

resolve: function(){
    // arguments[0]是resolve的第一個參數
    while(true){
        if( this.doneList.length === 0 ){
            this.state = 'done';
            break;
        }
        // 這裏是運行then裏面回調函數的地方
        this.doneList.shift().apply(this);
    }
}

如何修改呢?除了第一次傳遞參數,是把resolve的參數往下傳遞,其他的都是把上次的結果做爲下次開始(參數)。
因而,咱們能夠先把上次doneList裏面的函數運行結果保存起來。而後,等到下次須要的時候,再傳給下一個回調函數。
代碼修改:函數

resolve: function(){
    // arguments[0]是resolve的第一個參數
    var arg = arguments[0];
    while(true){
        if( this.doneList.length === 0 ){
            this.state = 'done';
            break;
        }
        // 這裏是運行then裏面回調函數的地方
        // 以數組形式傳給下一個函數,而後保存新的值
        // 判斷傳遞的參數是否爲undefined,是的話,就不用傳了
        if( typeof arg === 'undefined' ){
            arg = this.doneList.shift().apply(this);
        }else{
            arg = this.doneList.shift().apply(this, [arg]);
        }   
    }
    // 保存最後的arg,保證後續的回調能繼續獲得參數
    this.arg = arg;
}
// 還須要修改then方法
then: function(callback){ 
    this.doneList.push(callback); 
    if( this.state === 'done'){
        this.state = 'pending';
        this.resolve(this.arg); // 注意這裏也要傳遞參數
    }
    return this; 
}

第一次修改完善的代碼,及測試結果測試

function Promise(func){
    this.state = 'pending';
    this.doneList = []; 
    func(this.resolve.bind(this)); 
}

Promise.prototype = {
    resolve: function(){
        // arguments[0]是resolve的第一個參數
        var arg = arguments[0];
        while(true){
            if( this.doneList.length === 0 ){
                this.state = 'done';
                break;
            }
            // 這裏是運行then裏面回調函數的地方
            // 以數組形式傳給下一個函數,而後保存新的值
            // 判斷傳遞的參數是否爲undefined,是的話,就不用傳了
            if( typeof arg === 'undefined' ){
                arg = this.doneList.shift().apply(this);
            }else{
                arg = this.doneList.shift().apply(this, [arg]);
            }   
        }
        // 保存最後的arg,保證後續的回調能繼續獲得參數
        this.arg = arg;
    },
    then: function(callback){ 
        this.doneList.push(callback); 
        if( this.state === 'done'){
            this.state = 'pending';
            this.resolve(this.arg); // 注意這裏也要傳遞參數
        }
        return this; 
    }
}

// 測試
new Promise(function(resolve){
    resolve(1)
}).then(function(data){
    console.log(data); // 1
    return 2;
}).then(function(data){
    console.log(data); // 2
});

結果截圖:
圖片描述this

今天的第一個功能已經完了,那麼如今開始開發第二個功能。spa

先看一個測試prototype

new Promise(function(resolve){
    resolve(1)
}).then(function(data){
    console.log(data, 2); // 1,2
    return new Promise(function(resolve){
        window.setTimeout(function(){
            resolve(3);
        }, 1000);
    }).then(function(data){
        console.log(data, 4); // 3,4
        return 5;
    });
}).then(function(data){
    console.log(data, 6); // 5, 6
});

測試結果
圖片描述

我在上面測試例子中,then回調函數中返回的promise中故意使用了延遲函數。可是,輸出結果中5日後傳了,而且[5,6]是在[3,4]以後,且都有一秒中的延遲。

圖片描述
若是沒有回調返回一個promise,程序會一直按照第一行走下去,就算回調中有其餘promise(只要不return),也是兩條並行的線。一旦返回promise,新的promise會在這個點插入,而且原來尚未執行的回調,也會排到新的回調列表後面了。

先來修改resolve方法,由於回調函數都是在這裏運行的。

resolve: function(){
    // arguments[0]是resolve的第一個參數
    var arg = arguments[0];
    while(true){
        if( this.doneList.length === 0 ){
            this.state = 'done';
            break;
        }
        /*************************/
        if( arg instanceof Promise ){
            // 把新的promise保存起來,待會要用
            this.promise = arg;
            // 本promise沒有執行完的回調所有加入到新的回調列表
            arg.doneList = arg.doneList.concat(this.doneList);
            // 改變回調及狀態
            this.doneList.length = 0;
            this.state = 'done';
            // 跳出循環
            break;
        }
        /*************************/
        // 這裏是運行then裏面回調函數的地方
        // 以數組形式傳給下一個函數,而後保存新的值
        // 判斷傳遞的參數是否爲undefined,是的話,就不用傳了
        if( typeof arg === 'undefined' ){
            arg = this.doneList.shift().apply(this);
        }else{
            arg = this.doneList.shift().apply(this, [arg]);
        }   
    }
    // 保存最後的arg,保證後續的回調能繼續獲得參數
    this.arg = arg;
}

then: function(callback){ 
    this.doneList.push(callback); 
    if( this.state === 'done'){
        this.state = 'pending';
        this.resolve(this.arg); // 注意這裏也要傳遞參數
    }
    // 這裏不能在返回this了,而是一個promise對象
    return this.promise; 
}

// 若是then沒有返回promise,那麼this.promise = this;

function Promise(func){
    this.state = 'pending';
    this.doneList = []; 
    func(this.resolve.bind(this));
    // 默認指向自己
    this.promise = this; 
}

本期完整代碼

function Promise(func){
    this.state = 'pending';
    this.doneList = []; 
    func(this.resolve.bind(this));
    this.promise = this; 
}

Promise.prototype = {
    resolve: function(){
        // arguments[0]是resolve的第一個參數
        var arg = arguments[0];
        while(true){
            if( this.doneList.length === 0 ){
                this.state = 'done';
                break;
            }
            if( arg instanceof Promise ){
                this.promise = arg;
                arg.doneList = arg.doneList.concat(this.doneList);
                this.doneList.length = 0;
                this.state = 'done';
                break;
            }
            // 這裏是運行then裏面回調函數的地方
            // 以數組形式傳給下一個函數,而後保存新的值
            // 判斷傳遞的參數是否爲undefined,是的話,就不用傳了
            if( typeof arg === 'undefined' ){
                arg = this.doneList.shift().apply(this);
            }else{
                arg = this.doneList.shift().apply(this, [arg]);
            }   
        }
        // 保存最後的arg,保證後續的回調能繼續獲得參數
        this.arg = arg;
    },
    then: function(callback){ 
        this.doneList.push(callback); 
        if( this.state === 'done'){
            this.state = 'pending';
            this.resolve(this.arg); // 注意這裏也要傳遞參數
        }
        return this.promise; 
    }
}

結束。謝謝你們閱讀,若有錯誤或建議請給我留言或者發私信。

相關文章
相關標籤/搜索