zoukankan      html  css  js  c++  java
  • 转: Promises与Javascript异步编程

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

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

    嵌套式回调

    1. setTimeout(function() {
    2.     setTimeout(function() {
    3.     // do something
    4.     }, 10)
    5. }, 100);
    6. $.ajax(url, function() {
    7.         $.ajax(url2, function() {
    8.                 $.ajax(url3, function() {
    9.             // do something
    10.         });
    11.     });
    12. });

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

    异步函数类型

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

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

    异步函数异常捕获

    1. try {
    2.     setTimeout(function A() {
    3.         setTimeout(function B() {
    4.             setTimeout(function C() {
    5.                 throw new Error('Error');
    6.             }, 0);
    7.         }, 0);
    8.     }, 0);
    9. } catch (e) {}

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

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

    分布式事件

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

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

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

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

    1. var PubSub = (function() {
    2.     var _handlers = {};
    3.     return {
    4.         // 订阅事件
    5.         on: function(eventType, handler) {
    6.             if (!_handlers[eventType]) {
    7.                 _handlers[eventType] = [];
    8.             }
    9.         if (typeof handler == 'function') {
    10.             _handlers[eventType].push(handler);
    11.         }
    12.         },
    13.         //发布事件
    14.         emit: function(eventType) {
    15.             var args = Array.prototype.slice.call(arguments, 1);
    16.             var handlers = _handlers[eventType] || [];
    17.             for (var i = 0, len = handlers.length; i < len; i++) {
    18.                 handlers[i].apply(null, args)
    19.             }
    20.         }
    21.     };
    22. })();

    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:实现状态由未完成到拒绝(失败)

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

    1. // 这里假设Promise是一个已实现的Promise对象
    2. function asyncFn1() {
    3.     var p = new Promise();
    4.     setTimeout(function() {
    5.         console.log(1);
    6.         p.resolve(); // 标记为已完成
    7.     }, 2000);
    8.     return p;
    9. }
    10. function asyncFn2() {
    11.     var p = new Promise();
    12.     setTimeout(function() {
    13.         console.log(2);
    14.         p.reject('error'); // 标记为拒绝
    15.     }, 1000);
    16.     return p;
    17. }
    18. asyncFn1()
    19.     .then(function() {
    20.         return asyncFn2();
    21.     }).then(function() {
    22.         console.log('done');
    23.     }, function(err) {
    24.         console.log(err);
    25.     });

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

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

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

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

  • 相关阅读:
    防止网站被镜像,被iframe
    PHP实现图片批量压缩
    常规正则表达式
    git安装项目步骤
    Laravel创建自定义 Artisan 控制台命令实例教程
    git常规命令
    JS验证身份证号
    Lucene-索引库的维护
    Lucene-分词器
    Lucene-全文检索
  • 原文地址:https://www.cnblogs.com/stephenykk/p/4182603.html
Copyright © 2011-2022 走看看