资讯专栏INFORMATION COLUMN

实现简易 ES6 Promise 功能 (二)

sPeng / 3274人阅读

摘要:今天我们接着上次的内容继续扯,如何实现数据传递以及当回调函数返回一个新的上篇已完成的代码测试代码上面的结果,就是我们要实现的。然后,等到下次需要的时候,再传给下一个回调函数。先来修改方法,因为回调函数都是在这里运行的。

上一篇文章【实现简易 ES6 Promise 功能 (一)】实现了基本的异步功能。今天我们接着上次的内容继续扯,如何实现【数据传递】以及当【回调函数返回一个新的promise】

上篇已完成的代码

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

测试代码

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里面的函数作为参数,以此类推。

关键代码

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

结果截图:

今天的第一个功能已经完了,那么现在开始开发第二个功能。

先看一个测试

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

结束。谢谢大家阅读,如有错误或建议请给我留言或者发私信。

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

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

相关文章

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

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

    coordinate35 评论0 收藏0
  • 3行代码实现一个简易promise

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

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

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

    dance 评论0 收藏0
  • Week4 优质文章整理

    摘要:错过了一周的优质内容,不要再错过周一的快速回顾一周深度揭秘启动全过程翻译组每周社区问答入门语言简明入门与提高一只爬虫崔小拽爬虫知乎用户数据爬取和分析如何学习开源动效分析二动画最佳实践一工具箱之生命周期工具箱之权限管理一步步创建自己的框 错过了一周的优质内容,不要再错过周一的快速回顾 一周 fir.im Weekly -《深度揭秘 App 启动全过程》 SwiftGG翻译组 -《每周 S...

    hiYoHoo 评论0 收藏0
  • Week4 优质文章整理

    摘要:错过了一周的优质内容,不要再错过周一的快速回顾一周深度揭秘启动全过程翻译组每周社区问答入门语言简明入门与提高一只爬虫崔小拽爬虫知乎用户数据爬取和分析如何学习开源动效分析二动画最佳实践一工具箱之生命周期工具箱之权限管理一步步创建自己的框 错过了一周的优质内容,不要再错过周一的快速回顾 一周 fir.im Weekly -《深度揭秘 App 启动全过程》 SwiftGG翻译组 -《每周 S...

    call_me_R 评论0 收藏0

发表评论

0条评论

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