实现简易 ES6 Promise 功能 (一)

Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算。一个Promise对象表明着一个还未完成,但预期未来会完成的操做。app

先来一个例子 A 熟悉下语法异步

var p = new Promise(function(resolve, reject){
        console.log('1');
        // 运行后续的 callback 列表,例如:then,when等。不然,不会执行then里面的函数
        resolve('go next'); 
    });
    
    // 只考虑成功
    p.then(function(){
        console.log(2, arguments);
        return 'next';
    }, null).then(function(){
        console.log(3, arguments)
    }, null);
    
    // 输出
    1
    2 ['go next']
    3 ['next']

最初的设想async

function Promise(func){ // 接收一个函数做为参数
    
    }
    
    Promise.prototype = {
    
        then: function(callback){ // 接收函数做为参数
            
            return this; // 支持链式调用
        }
    }

观察例 A,resolve是一个函数,而且不是用户传的,全部Promise自身应该有一个resolve方法,而且这个方法要传递给Promise构造器里面的函数做为参数。函数

function Promise(func){ // 接收一个函数做为参数
        **func(this.resolve);**
    }
    
    Promise.prototype = {
        
        **resolve: function(){
        
        }**,
        
        then: function(callback){ // 接收函数做为参数
            
            return this; // 支持链式调用
        }
    }

Promise是按照顺序来执行callback的,而且由resolve触发。测试

function Promise(func){ // 接收一个函数做为参数
        **this.doneList = []; // callback 列表**
        **func(this.resolve.bind(this)); // 顺带绑定this对象**
    }
    
    Promise.prototype = {
        
        resolve: function(){
            **//执行回调列表
            while(true){
                if( this.doneList.length === 0 ){
                    break;
                }
                this.doneList.shift().apply(this);
            }**
        },
        
        then: function(callback){ // 接收函数做为参数
            **this.doneList.push(callback); // 加入到回调队列**
            return this; // 支持链式调用
        }
    }

好,如今写一个测试用例this

var p =new Promise(function(resolve){
            console.log('a');
            resolve();
        }).then(function(){
            console.log('b');
        });
        
     // 输出
     'a'

什么鬼?打印下pspa

console.log(p);

图片描述

咱们发现原来doneList里面还有一个函数没有运行,再运行下这个函数prototype

p.doneList[0].call(this);
    
    //结果
    console.log('b'); // 打印 b

打断点跟踪,发现Promise先执行resolve方法,而后执行then,把函数push到doneList。可是,再也没有执行过doneList里面的函数了。怎么办呢?咱们能够给Promise加一个属性(state)来描述当前状态,分为【未完成】(pending)和【完成】(done)。若是执行then时,状态已是完成态,那么切换到未完成态,并执行resolve方法。code

function Promise(func){ // 接收一个函数做为参数
        **this.state = 'pending'; // 初始化状态**
        this.doneList = []; // callback 列表
        func(this.resolve.bind(this)); // 顺带绑定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 = 'pneding';
                this.resolve();
            }
            
            return this; // 支持链式调用
        }
    }

用和上面相似的例子再次测试对象

var p =new Promise(function(resolve){
            console.log('a');
            resolve();
        }).then(function(){
            console.log('b');
        }).then(function(){
            console.log('c');
        });

结果截图
图片描述

这下,咱们自定义的Promise基础功能完成了最核心的部分了。也许有人会疑问,你这写的什么鬼?下面的代码更简单,也能实现相同的功能

function Promise(func){ // 接收一个函数做为参数
   
        func(this.resolve.bind(this)); // 顺带绑定this对象
    }
    
    Promise.prototype = {
        
        resolve: function(){
            //什么也不干    
        },
        
        then: function(callback){ // 也是接收函数
            callback.call(this); // 直接运行
            return this; // 支持链式调用
        }
    }

测试用例

var p =new Promise(function(resolve){
            console.log('d');
            resolve();
        }).then(function(){
            console.log('e');
        }).then(function(){
            console.log('f');
        });

结果:
图片描述

可是,文章最前面说过

Promise 对象用于延迟(deferred) 计算和异步(asynchronous ) 计算

而且会顺序执行回调列表(doneList)。最终代码及测试

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; 
        }
    }

    var p = new Promise(function(resolve){
            window.setTimeout(function(){
                console.log('d');
                resolve();
            }, 1000);
        }).then(function(){
            console.log('e');
        }).then(function(){
            console.log('f');
        });

    console.log('被阻塞了吗?');

输出:
图片描述

先输出'被阻塞了吗?',一秒钟后相继输出 d、e、f 。能够看出,不但没有阻塞后面的代码执行,并且回调也是按照顺序执行的。

结束。

下篇继续完善,例如数据传递以及then中函数返回一个Promise时,如何处理。欢迎你们有疑问或者建议,一块儿来交流。

相关文章
相关标签/搜索