资讯专栏INFORMATION COLUMN

浅谈Javascript中Promise对象的实现

caiyongji / 2952人阅读

摘要:我们可以进行适当的改进,把回调函数写到外面即使是改写成这样,代码还是不够直观,但是如果有了对象,代码就可以写得非常清晰,一目了然,请看这样函数就不用写在的回调中了目前的标准中还未支持对象,那么我们就自己动手,丰衣足食吧。

本文同步自我得博客:http://www.joeray61.com

很多做前端的朋友应该都听说过Promise(或者Deferred)对象,今天我就讲一下我对Promise的认识

What?

PromiseCommonJS的规范之一,拥有resolverejectdonefailthen等方法,能够帮助我们控制代码的流程,避免函数的多层嵌套。如今异步在web开发中越来越重要,对于开发人员来说,这种非线性执行的编程会让开发者觉得难以掌控,而Promise可以让我们更好地掌控代码的执行流程,jQuery等流行的js库都已经实现了这个对象,年底即将发布的ES6也将原生实现Promise

Why

想象这样一个场景,两个异步请求,第二个需要用到第一个请求成功的数据,那么我们代码可以这样写

    ajax({
        url: url1,
        success: function(data) {
            ajax({
                url: url2,
                data: data,
                success: function() {
                }
            });
        }
    });

如果继续下去在回调函数中进行下一步操作,嵌套的层数会越来越多。我们可以进行适当的改进,把回调函数写到外面

    function A() {
        ajax({
            url: url1,
            success: function(data) {
                B(data);
            }
        });
    }
    function B(data) {
        ajax({
            url: url2,
            success: function(data) {
                ......
            }
        });
    }

即使是改写成这样,代码还是不够直观,但是如果有了Promise对象,代码就可以写得非常清晰,一目了然,请看

new Promise(A).done(B);

这样函数B就不用写在A的回调中了

How

目前的ES标准中还未支持Promise对象,那么我们就自己动手,丰衣足食吧。思路大致是这样的,用2个数组(doneListfailList)分别存储成功时的回调函数队列和失败时的回调队列

state: 当前执行状态,有pendingresolvedrejected3种取值

done: 向doneList中添加一个成功回调函数

fail: 向failList中添加一个失败回调函数

then: 分别向doneListfailList中添加回调函数

always: 添加一个无论成功还是失败都会调用的回调函数

resolve: 将状态更改为resolved,并触发绑定的所有成功的回调函数

reject: 将状态更改为rejected,并触发绑定的所有失败的回调函数

when: 参数是多个异步或者延迟函数,返回值是一个Promise兑现,当所有函数都执行成功的时候执行该对象的resolve方法,反之执行该对象的reject方法
下面是我的具体实现过程:

var Promise = function() {
    this.doneList = [];
    this.failList = [];
    this.state = "pending";
};

Promise.prototype = {
    constructor: "Promise",
    resolve: function() {
        this.state = "resolved";
        var list = this.doneList;
        for(var i = 0, len = list.length; i < len; i++) {
            list[0].call(this);
            list.shift();
        }
    },
    reject: function() {
        this.state = "rejected";
        var list = this.failList;
        for(var i = 0, len = list.length; i < len; i++){
            list[0].call(this);
            list.shift();
        }
    },
    done: function(func) {
        if(typeof func === "function") {
            this.doneList.push(func);
        }
        return this;
    },
    fail: function(func) {
        if(typeof func === "function") {
            this.failList.push(func);
        }
        return this;
    },
    then: function(doneFn, failFn) {
        this.done(doneFn).fail(failFn);
        return this;
    },
    always: function(fn) {
        this.done(fn).fail(fn);
        return this;
    }
};

function when() {
    var p = new Promise();
    var success = true;
    var len = arguments.length;
    for(var i = 0; i < len; i++) {
        if(!(arguments[i] instanceof Promise)) {
            return false;
        }
        else {
            arguments[i].always(function() {
                if(this.state != "resolved"){
                    success = false;
                }
                len--;
                if(len == 0) {
                    success ? p.resolve() : p.reject();
                }
            });
        }
    }
    return p;
}
Improve

目前只是实现了Promise的基础功能,但仍然还有无法处理的情况,例如要实现3个或3个以上的异步请求的串行,目前我的Promise没有办法支持new Promise(A).then(B).then(C)这样的形式,jQuery在1.7的版本中为Deferred(Promise)对象实现了pipe函数,可以通过这个函数实现上述功能,代码为$.Deferred(A).pipe(B).then(C),我尝试去读了jQuery这部分的代码,但是没能读懂,希望有大神能够给一些实现思路

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

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

相关文章

  • 浅谈JavaScript事件循环机制

    摘要:事件循环背景是一门单线程非阻塞的脚本语言,单线程意味着,代码在执行的任何时候,都只有一个主线程来处理所有的任务。在意识到该问题之际,新特性中的可以让成为一门多线程语言,但实际开发中使用存在着诸多限制。这个地方被称为执行栈。 事件循环(Event Loop) 背景 JavaScript是一门单线程非阻塞的脚本语言,单线程意味着,JavaScript代码在执行的任何时候,都只有一个主线程来...

    Pluser 评论0 收藏0
  • 浅谈ES6原生Promise

    摘要:如果有错误,则到的第二个回调函数中,对错误进行处理。假设第一个的第一个回调没有返回一个对象,那么第二个的调用者还是原来的对象,只不过其的值变成了第一个中第一个回调函数的返回值。 ES6标准出炉之前,一个幽灵,回调的幽灵,游荡在JavaScript世界。 正所谓: 世界本没有回调,写的人多了,也就有了})})})})})。 Promise的兴起,是因为异步方法调用中,往往会出现回调函数一...

    yedf 评论0 收藏0
  • 浅谈async·await

    摘要:在语言中,函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数。为什么里面必须使用函数呢,因为我们需要确保传入的值只有一个,利用其回调函数,来进行递归自动控制函数的流程,接收和交还程序的执行权 前言 这篇文章主要是梳理一下自己对阮一峰大神写的关于async/await文章,有写得不对的地方以及理解得不对的地方,各位大佬请指错! 对比 简单对比传统异步,...

    Magicer 评论0 收藏0
  • 浅谈不同环境下JavaScript执行机制 + 示例详解

    摘要:如果没有其他异步任务要处理比如到期的定时器,会一直停留在这个阶段,等待请求返回结果。执行的执行事件关闭请求的,例如事件循环的每一次循环都需要依次经过上述的阶段。因此,才会早于执行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任务(Synchronous) 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务 ...

    wanghui 评论0 收藏0
  • [前端工坊]浅谈Web编程异步调用发展演变

    摘要:三即生成器,它是生成器函数返回的一个对象,是中提供的一种异步编程解决方案而生成器函数有两个特征,一是函数名前带星号,二是内部执行语句前有关键字调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的迭代器对象。 文章来自微信公众号:前端工坊(fe_workshop),不定期更新有趣、好玩的前端相关原创技术文章。 如果喜欢,请关注公众号:前端工坊版权归微信公众号所有,转载请...

    qpwoeiru96 评论0 收藏0

发表评论

0条评论

caiyongji

|高级讲师

TA的文章

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