资讯专栏INFORMATION COLUMN

实现简易 ES6 Promise 功能 (一)

coordinate35 / 1262人阅读

摘要:对象用于延迟计算和异步计算。一个对象代表着一个还未完成,但预期将来会完成的操作。接收一个函数作为参数接收函数作为参数支持链式调用是按照顺序来执行的,并且由触发。下篇继续完善,例如数据传递以及中函数返回一个时,如何处理。

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

先来一个例子 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"]

最初的设想

    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; // 支持链式调用
        }
    }

好,现在写一个测试用例

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

什么鬼?打印下p

    console.log(p);

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

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

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

    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时,如何处理。欢迎大家有疑问或者建议,一起来交流。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78535.html

相关文章

  • 实现简易 ES6 Promise 功能 (二)

    摘要:今天我们接着上次的内容继续扯,如何实现数据传递以及当回调函数返回一个新的上篇已完成的代码测试代码上面的结果,就是我们要实现的。然后,等到下次需要的时候,再传给下一个回调函数。先来修改方法,因为回调函数都是在这里运行的。 上一篇文章【实现简易 ES6 Promise 功能 (一)】实现了基本的异步功能。今天我们接着上次的内容继续扯,如何实现【数据传递】以及当【回调函数返回一个新的prom...

    sPeng 评论0 收藏0
  • 3行代码实现简易promise

    前言 作为一个后端过来的同学,刚入门前端的时候,被js种种「反人类」的概念折腾的死去活来的.其中一个印象比较深刻的,就是promise,感觉实在太难理解了...所有就有了写个简单的promise的想法.希望能帮助到一些跟我一样,感觉promise很难理解的新同学. promise的教程网上多如牛毛,其中写的比较通俗易懂的莫过于阮一峰的es6,反正我是他的书才懂的.所以今天,我们也不会来复述一遍如何...

    ralap 评论0 收藏0
  • 异步发展流程 —— Generators + co 让异步更优雅

    摘要:遍历器原有的表示集合的数据结构,主要有和,在中又加入了和,这样就有了四种数据集合,还可以组合使用它们,如数组的成员是或,这样就需要一种统一的接口机制,用来处理所有不同的数据结构。 showImg(https://segmentfault.com/img/remote/1460000018998438?w=900&h=431); 阅读原文 Generators 简介 Generato...

    dingda 评论0 收藏0
  • js处理异步函数:从callback到promise

    摘要:在处理异步回调函数的情况有着越来越值得推崇的方法及类库,下面会依次介绍处理异步函数的发展史,及源码解读。而对象的状态,是由第一个的参数成功回调函数或失败回调函数的返回值决定的。 函数的执行分为同步和异步两种。同步即为 同步连续执行,通俗点讲就是做完一件事,再去做另一件事。异步即为 先做一件事,中间可以去做其他事情,稍后再回来做第一件事情。同时还要记住两个特性:1.异步函数是没有返回值的...

    dance 评论0 收藏0
  • JavaScript之手写Promise

    摘要:如果状态是等待态的话,就往回调函数中函数,比如如下代码就会进入等待态的逻辑以上就是简单版实现实现一个符合规范的接下来大部分代码都是根据规范去实现的。 为更好的理解, 推荐阅读Promise/A+ 规范 实现一个简易版 Promise 在完成符合 Promise/A+ 规范的代码之前,我们可以先来实现一个简易版 Promise,因为在面试中,如果你能实现出一个简易版的 Promise ...

    stefan 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<