Promises与Javascript异步编程

问说网 · 发布于 2014-04-17 · 字数4600 · 浏览 2381 · 评论 0

在如今都追求用户体验的时代,Ajax应用真的是无所不在。加上这些年浏览器技术、HTML5以及CSS3等的发展,越来越多的富Web应用出现;在给与我们良好体验的同时,Web开发人员在背后需要处理越来越多的异步回调逻辑。

笔者对最近读完的《Async Javascript-Build More Responsive Apps with Less Code》(Javascript异步编程-设计快速响应的网络应用)一书以及部分资料,整理了我认为比较重要的一些点以及容易理解错的地方,使大家对 Promise对象以及异步编程有更深的认识。

嵌套式回调

setTimeout(function() {
    setTimeout(function() {
    // do something
    }, 10)
}, 100);

$.ajax(url, function() {
        $.ajax(url2, function() {
                $.ajax(url3, function() {
            // do something
        });
    });
});

可是问题来了,当我们的嵌套越多,代码结构层级会变得越来越深。首先是阅读上会变得困难;其次是强耦合,接口变得不好扩展。我们需要一种模式来解决这种问题,这就是Promises所要做的事情。

异步函数类型

Javascript里异步函数可以分为两大类型:

  • I/O函数(Ajax、script…)
  • 计时函数(setTimeout、setInterval、setImmediate)

异步函数异常捕获

try {
    setTimeout(function A() {
        setTimeout(function B() {
            setTimeout(function C() {
                throw new Error('Error');
            }, 0);
        }, 0);
    }, 0);
} catch (e) {}

运行以上代码,A、B、C被添加到事件队列里;异常触发时,A、B已被移出事件队列,内存堆栈里只存在C,此时的异常不被try捕获,只会流向应用程序未捕获异常处理器。

所以,在异步函数里,不能使用try/catch捕获异常。

分布式事件

Javascript的事件核心是事件分发机制,通过对发布者绑定订阅句柄来达到异步相响应的目的:

document.onclick = function() {
    // click
};

PubSub(Publish/Subscribe, 发布/订阅)模式,就是这么一种模式,通过订阅发布者的事件响应来达到多层分发解耦的目的。

以下是一个简单版本的PubSub模式实现:

var PubSub = (function() {
    var _handlers = {};
    return {
        // 订阅事件
        on: function(eventType, handler) {
            if (!_handlers[eventType]) {
                _handlers[eventType] = [];
            }
        if (typeof handler == 'function') {
            _handlers[eventType].push(handler);
        }
        },
        //发布事件
        emit: function(eventType) {
            var args = Array.prototype.slice.call(arguments, 1);
            var handlers = _handlers[eventType] || [];
            for (var i = 0, len = handlers.length; i < len; i++) {
                handlers[i].apply(null, args)
            }
        }
    };
})();

Promises/A规范

CommonJS之Promises/A规范是Kris Zyp于2009年提出来的,它通过规范API接口来简化异步编程,使我们的异步逻辑代码更易理解。

遵循Promises/A规范的实现我们称之为Promise对象,Promise对象有且仅有三种状态:unfulfilled(未完成)、 fulfilled(已完成)、failed(失败/拒绝);而且状态变化只能从unfulfilled到fulfilled,或者 unfulfilled到failed;

Promise对象需实现一个then接口,then(fulfilledHandler, errorHandler, progressHandler);then接口接收一个成功回调(fulfilledHandler)与一个失败回调(errorHandler);progressHandler触发回调是可选的,Promise对象没有强制去回调此句柄。

then方法的实现需要返回一个新的Promise对象,以形成链式调用,或者叫Promise管道。

为了实现状态的转变,我们还需要实现另外两个接口:

  • resolve:实现状态由未完成到已完成
  • reject:实现状态由未完成到拒绝(失败)

这样子我们开篇所说的嵌套式回调就可以这样子写了:

// 这里假设Promise是一个已实现的Promise对象
function asyncFn1() {
    var p = new Promise();
    setTimeout(function() {
        console.log(1);
        p.resolve(); // 标记为已完成
    }, 2000);
    return p;
}
function asyncFn2() {
    var p = new Promise();
    setTimeout(function() {
        console.log(2);
        p.reject('error'); // 标记为拒绝
    }, 1000);
    return p;
}

asyncFn1()
    .then(function() {
        return asyncFn2();
    }).then(function() {
        console.log('done');
    }, function(err) {
        console.log(err);
    });

有了Promise,我们可以以同步的思维去编写异步的逻辑了。在同步函数的世界里,有2个非常重要的概念:

  • 有返回值
  • 可以抛出异常

Promise不仅仅是一种可以链式调用的对象,更深层次里,它为异步函数与同步函数提供了一种更加直接的对应关系。

上面我们说过,在异步函数里,不能使用try/catch捕获异常,因此也不能抛出异常。有了Promise,只要我们显式定义了errorHandler,那么我们就可以做到像同步函数那样的异常捕获了。

转载:http://www.zawaliang.com/2013/08/399.html

本文系作者 问说网 授权问说网发表,并经问说网编辑,转载请注明出处和 本文链接

相关文章

  • 2015-02-14HTML中的CSS盒子模型边界(box-model)问题详解
  • 2015-08-28初识Geolocation API获取用户的物理地址
  • 2017-01-19用JavaScript实现给出的盒子的序列是否可连为一矩型
  • 2016-12-02FlyJSONP轻量级的跨域AJAX请求插件
  • 2016-03-28关于JavaScript中Math.random()的生成
  • 2016-05-16当我们谈论极简设计,我们需要注意些什么?
  • 2016-05-16快速搞定配色!掌握3个实用方法快速搞定配色
  • 2016-05-16图标设计的几个小建议!如何让图标更具识别度
  • 发布评论

    为您推荐

    推聊基于极光推送的Android手机聊天系统
    Vincent · 发布于 2015-11-18

    推聊基于极光推送的Android手机聊天系统

    推聊是一个基于极光推送的Android手机聊天系统。支持群聊与点对点聊天。当前包括Android客户端与Java服务器端。3分钟就可以整套系统跑起来。

    问说网 · 发布于 2016-03-02

    在PHP获取TTF格式的字体英文名和中文名

    PHP可真是万能的,能够打开文件查看源码,并且能够获取里面的内容,按照特定的编码即可,这不今天给大家分享一下在PHP获取TTF格式的字体英文名和中文名的方法。

    问说网 · 发布于 2016-12-02

    Response JS创建高性能的支持移动设备的网站

    Response JS 是一个轻量级的 jQuery 插件,用来创建高性能的支持移动设备的网站。它提供了一套语法用来根据不同的设备环境动态替换HTML代码。例如…

    问说网 · 发布于 2016-05-16

    jQuery.ish简化压缩版的jQuery库

    jQuery.ish 是一个简化版的 jQuery,与 jQuery 完全兼容,当你不希望使用 jQuery 这么大的库时可以考虑使用。原始大小只有 1.7K,…

    写实日历图标教程

    这样。 更一下。 【1】观察这个图标,我们将它分成三个部分来制作。如下图所示。 ①日历的卷页 ②日历的夹子和金属环 ③底座 【2】新建一个700x800的画布,…

    • 写实日历图标教程
    • 写实日历图标教程
    • 写实日历图标教程
    • 写实日历图标教程
    CecilliaQuinn · 发布于 2016-05-17 · 浏览 890 · 评论 0
    Vincent · 发布于 2016-07-06

    Java接口和抽象类

    抽象类 抽象类中的方法既可以有抽象方法,也可以有非抽象方法,可以全部都是抽象方法,也可以全部都是非抽象方法 抽象方法只能出现在抽象类或接口中,不能出现在非抽象类…

    Vincent · 发布于 2016-07-06

    Spring MVC文件上传

    1.    文件配置 SpringMVC 用的是 的MultipartFile来进行文件上传 所以我们首先要配置MultipartResolver来明确告诉Di…

    Vincent · 发布于 2016-07-06

    SSH环境搭建

    Struts部分 web.xml中配置: <filter>     <filter-name>struts2</filter-na…

    问说网手机版

    躺着 站着 跪着轻松访问

    更多详情 关于作者

    问说网

    问说网分享与设计有关的文章素材界面和作品,提供设计教程、素材分享、界面欣赏、编程设计、设计书籍、设计师导航等内容,你可以在这里阅读、学习、分享、交流。

    13130 文章
    494 评论
    2012 人气

    更多 热门话题

    APP界面

    关注 APP界面

    文章 41506 · 浏览 2384

    APP欣赏

    关注 APP欣赏

    文章 41427 · 浏览 2257

    APP手机界面

    关注 APP手机界面

    文章 41417 · 浏览 2307

    图片素材

    关注 图片素材

    文章 29463 · 浏览 1790

    高清图片

    关注 高清图片

    文章 26530 · 浏览 1951

    更多 推荐作者

    关注 秋末残雪

    文章 106 · 评论 0

    关注 秋天的孤寂

    文章 99 · 评论 0

    关注 惢碎葬爱

    文章 96 · 评论 0

    关注 溫柔的溫柔

    文章 91 · 评论 0

    关注 走了留下什么

    文章 110 · 评论 0

    关注 莪很迷茫

    文章 97 · 评论 0

    
    顶部 反馈 评论 底部

    意见反馈

    感谢您对问说网的支持,提出您在使用过程中遇到的问题或宝贵建议,您的反馈对我们产品的完善有很大帮助。

    您的反馈我们已收到!

    感谢您提供的宝贵意见,我们会在1-2个工作日,通过您留下的联系方式将处理结果反馈给您!