Promises与Javascript异步编程

问说网 · 发布于 2014-04-17 · 字数4600 · 浏览 2384 · 评论 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-12-02Response JS创建高性能的支持移动设备的网站
  • 2016-06-06PHP处理Checkbox多选框表单元素
  • 2016-06-28jqFloat.js实现页面元素的浮动效果jQuery插件
  • 2016-07-01SweetTooltip基于jQuery和CSS3链接工具提示插件
  • 2016-07-02jQuery Scroll Path按路径元素滚动动画插件
  • 2016-07-05环境搭建:php7.0.8 + Apache2.4 + MySQL5.7.13 + phpMyAdmin4.6.3
  • 发布评论

    为您推荐

    问说网 · 发布于 2014-09-19

    javascript数据类型转换的方法总结

    在编写js代码的时候,经常会用到数据类型转换,必须获取到的div高度,默认后面带有单位,那么如何把这个单位去掉,将字符串转换为整数类型的变量呢,今天我们就来谈谈…

    十分钟搞清字符集和字符编码
    问说网 · 发布于 2016-07-15

    十分钟搞清字符集和字符编码

    在介绍字符集之前,我们先了解下为什么要有字符集。我们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。

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

    HTML5是否真的需要Picture标签?

    responsive design 并不是 responsive image,它能创建适应性的布局可以缩放图片但不能智能加载适应屏幕大小的图片。在小尺寸屏幕上缩…

    XLSX.js转换BASE64编码的XLSX文件为JavaScript对象
    问说网 · 发布于 2015-12-04

    XLSX.js转换BASE64编码的XLSX文件为JavaScript对象

    XLSX.js 是一个用来转换 BASE64 编码的 XLSX 文件数据为 JavaScript 对象,也支持 JavaScript 对象到 XLSX 数据的转…

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

    FlyJSONP轻量级的跨域AJAX请求插件

    FlyJSONP是一个JavaScript库,用于实现跨域GET和POST请求服务,支持JSONP,并取得一个JSON格式的数据响应,这个Library具有易于…

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

    ScrollMagic神奇的滚动交互动画jQuery插件

    ScrollMagic 是一款 jQuery 插件,它让你可以像使用进度条一样使用滚动条。如果你想在特定的滚动位置开始一个动画,并且让动画同步滚动条的动作,或者…

    在Photoshop中创建绚丽的草木文字混合效果

    本次PS教程,主要向您展示“草木合成新颖视觉效果图”的制作过程,此次合成图片的制作将涉及到蒙板,图像调整,滤镜效果等工具,先来看看最终预览效果。

    • 在Photoshop中创建绚丽的草木文字混合效果
    • 在Photoshop中创建绚丽的草木文字混合效果
    • 在Photoshop中创建绚丽的草木文字混合效果
    • 在Photoshop中创建绚丽的草木文字混合效果
    问说网 · 发布于 2016-04-20 · 浏览 1122 · 评论 0

    看起来好酷!教你快速打造梦幻女神的重影效果

    今天CYHD借梦幻女神的教程,帮同学们掌握快速抠头发丝的技巧。在网页设计时,特别需要大图背景作为渲染整个网站的风格气氛,那么,感染力强的图片就是绝佳的选择。

    • 看起来好酷!教你快速打造梦幻女神的重影效果
    • 看起来好酷!教你快速打造梦幻女神的重影效果
    • 看起来好酷!教你快速打造梦幻女神的重影效果
    • 看起来好酷!教你快速打造梦幻女神的重影效果
    GrahamLydia · 发布于 2016-05-15 · 浏览 950 · 评论 0

    问说网手机版

    躺着 站着 跪着轻松访问

    更多详情 关于作者

    问说网

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

    13086 文章
    493 评论
    1865 人气

    更多 热门话题

    APP界面

    关注 APP界面

    文章 41506 · 浏览 1574

    APP欣赏

    关注 APP欣赏

    文章 41427 · 浏览 1506

    APP手机界面

    关注 APP手机界面

    文章 41417 · 浏览 1521

    图片素材

    关注 图片素材

    文章 29463 · 浏览 1026

    高清图片

    关注 高清图片

    文章 26530 · 浏览 1216

    更多 推荐作者

    关注 秋天的孤寂

    文章 99 · 评论 0

    关注 怎麽继续

    文章 90 · 评论 2

    关注 倾听寂寞

    文章 83 · 评论 0

    关注 溫柔的溫柔

    文章 91 · 评论 0

    关注 走了留下什么

    文章 110 · 评论 0

    关注 莪很迷茫

    文章 97 · 评论 0

    顶部 反馈 评论 底部

    意见反馈

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

    您的反馈我们已收到!

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