Promises与Javascript异步编程

问说网 · 发布于 2014-04-17 · 字数4600 · 浏览 2416 · 评论 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

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

相关文章

  • 2017-01-19用JavaScript实现给出的盒子的序列是否可连为一矩型
  • 2016-12-02FlyJSONP轻量级的跨域AJAX请求插件
  • 2016-07-02jQuery Scroll Path按路径元素滚动动画插件
  • 2016-07-06Java Web的安全验证机制
  • 2016-07-06Java初识
  • 2016-07-06Java中面向对象的封装和继承以及多态
  • 2016-07-06详细讲解JAVA中的IO流
  • 2016-07-06JBoss下WebService开发
  • 发布评论

    为您推荐

    问说网 · 发布于 2015-08-22

    Picturefill可选参数和JavaScript API介绍

    前面的一篇文章中介绍Picturefill的基本使用方法,接下来这篇文章将为大家介绍Picturefill的高级用法,其中包括可选的参数和属性使用,Pictur…

    用JavaScript实现给出的盒子的序列是否可连为一矩型
    AustenJuliet · 发布于 2017-01-19

    用JavaScript实现给出的盒子的序列是否可连为一矩型

    by cpglkg <script>var arr=[5,10,15];function rect(arr,width){ arr.sort(fun…

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

    SQLite数据库中的HASH算法实现

    SQLite的分词器模块需要对输入的字符串映射为系统中的标示符,其对关键字映射使用了HASH算法,其对HASH冲突的解决十分巧妙。

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

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

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

    简单几招提升你的设计

    UI系列实战第二篇,主要将图层样式的投影和渐变叠加的使用,这一次主要讲PS中图层样式的一些使用技巧,你喜欢或者不喜欢,教程就在这里,不弃不离。

    • 简单几招提升你的设计
    • 简单几招提升你的设计
    • 简单几招提升你的设计
    • 简单几招提升你的设计
    CroninBevis · 发布于 2016-05-17 · 浏览 1003 · 评论 0
    jQuery Scroll Path按路径元素滚动动画插件
    问说网 · 发布于 2016-07-02

    jQuery Scroll Path按路径元素滚动动画插件

    jQuery Scroll Path是一个jQuery的滚动路径插件,可以让你自定义滚动路径。该插件是使用canvas flavored的语法来绘制路径,并且支…

    angularAMD使用RequireJS和AngularJS快速构建WebApp
    问说网 · 发布于 2016-07-05

    angularAMD使用RequireJS和AngularJS快速构建WebApp

    angularAMD是作者 marcoslin 使用 RequireJS + AngularJS开发的前端mvvm框架,因此你可以使用它快速创建一款Web Ap…

    SVN
    Vincent · 发布于 2016-07-06

    SVN

    下载 Subversion(SVN服务端): 下载地址1 下载地址2 TortoiseSVN(SVN客户端): 下载地址1 下载地址2   安装 SV…

    问说网手机版

    躺着 站着 跪着轻松访问

    更多详情 关于作者

    问说网

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

    13130 文章
    495 评论
    2031 人气

    更多 热门话题

    APP界面

    关注 APP界面

    文章 41506 · 浏览 2562

    APP欣赏

    关注 APP欣赏

    文章 41427 · 浏览 2418

    APP手机界面

    关注 APP手机界面

    文章 41417 · 浏览 2466

    图片素材

    关注 图片素材

    文章 29463 · 浏览 1950

    高清图片

    关注 高清图片

    文章 26530 · 浏览 2133

    更多 推荐作者

    关注 秋天的孤寂

    文章 99 · 评论 0

    关注 惢碎葬爱

    文章 96 · 评论 0

    关注 怎麽继续

    文章 90 · 评论 2

    关注 倾听寂寞

    文章 83 · 评论 0

    关注 流浪的脚步

    文章 86 · 评论 0

    关注 籹孒不认输

    文章 94 · 评论 0

    
    顶部 反馈 评论 底部

    意见反馈

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

    您的反馈我们已收到!

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