《JavaScript应用程序设计》一一2.18 Promises与Deferreds

2.18 Promises与Deferreds

Promises作为一个对象,维护着成功与失败两个回调函数队列。与在异步/同步操作结束后执行的回调函数有所不同,你可以在异步操作的结尾处返回一个包含了一组回调函数的Promises。
Promises能够让你了解当前异步操作的进行状态,是在等待中,还是已完成,具体完成进度是多少。在整个过程中随时都可以向Promises中添加新的回调函数,当异步操作结束时,Promises会被正确解析,此时标识为成功的回调函数队列会被批量执行。
受CommonJS规范Promises/A的启发,jQuery实现了Promises并将这一规范推广至了JavaScript社区。jQuery使用Promises管理自己内部(包括Ajax请求在内)的异步任务队列,事实上,早在jQuery1.5中,所有Ajax方法执行后均会返回一个Promises,来看看它是如何工作的。

var whenDataFetched = $.getJSON(
  'https://graph.facebook.com/jsapplications'
);

asyncTest('Ajax promise API', function () {
  whenDataFetched
    .done(function (response) {
      ok(response,
        'The server returned data.');
      start();
    })
    .fail(function () {
      ok(true,
        'There was an error.');
      start();
    });
});

这个例子展示了,使用Ajax请求去获取“Programming JavaScript Applications”页面的元数据,因为所有jQuery中的Ajax辅助函数都会返回一个Promises,所以,你可以在whenDataFetched.done()中追加你的成功回调函数。
Promises与回调函数间的区别在于,Promises是调用者返回的一个对象,而不是传入调用者随后被执行的一个函数。Promises对象支持在异步操作过程中随时添加新的回调函数,并且会将回调函数彼此间的代码逻辑隔离开,所以使用Promises时回调函数并不一定要在异步操作开始前就传入。
deferred对象包含了一组方法,它被用来管理控制Promises。jQuery的Deferred()方法返回了一个与Promises功能极为类似的对象,这个对象上还拥有resolve()与reject()方法,这两个方法可以触发相应队列中的回调函数。假设你出于灵活性的考虑,想对现有的setTimeout()方法做改造,你想让它随时都可以接受回调函数的传入,而并不是仅能在首次定时调用时添加回调,你可以使用deferred对象来实现这个改造。

var timer = function timer(delay) {
  var whenTimedOut = $.Deferred(),
    promise = whenTimedOut.promise();

  promise.cancel = function (payload) {
    whenTimedOut.reject(payload);
  };

  setTimeout(function () {
    whenTimedOut.resolve();
  }, delay);

  return promise;
};

asyncTest('Deferred', function () {
  var startTime = new Date(),
    delay = 30,
    afterTimeout = 50,
    cancelTime = 100,
    myTimer = timer(delay),
    cancelTimer = timer(cancelTime);

  expect(4);

  myTimer.done(function () {
    ok(true,
      'First callback fired.');
  });

  myTimer.done(function () {
    var now = new Date();
    ok((now - startTime) > delay,
      'Delay works.'
      );
  });

  setTimeout(function () {
    ok(true,
      'Fires after timeout expires.');
  }, afterTimeout);

  setTimeout(function () {
    start();
  }, afterTimeout + 20);

  cancelTimer
    .done(function () {
      ok(false,
        'A canceled timer should NOT run .done().');
    })
    .fail(function () {
      ok(true,
        'A canceled timer calls .fail().');
    })
    .cancel();
});

Promises特别适用于那些有着一系列复杂调用序列的异步操作,因为往往在发起新的数据请求之前必须完成对多个数据源的请求。
回调函数会使得代码嵌套逻辑变得越来越深,但拥有了Promises,我们可以在任意数量的Promises对象被解析之后再决定下一步操作,下面是新timer()函数的应用:

var a = timer(60),
  b = timer(70),
  c = timer(40),
  tasks = [a, b, c];

asyncTest('Multiple dependencies.', function () {
  $.when(a, b, c).done(function () {
    ok(true, 'Runs when all promises resolve');
    start();
  });
});
时间: 2024-09-28 14:32:04

《JavaScript应用程序设计》一一2.18 Promises与Deferreds的相关文章

《JavaScript应用程序设计》导读

前言 在本书中我们先后提到了不少Web开发类书籍,但对于那些想从头开始学习构建完整JavaScript应用的读者来说,市面上真正值得推荐的JavaScript教程又显得十分稀缺.与此同时,现在几乎每一个互联网创业公司的人员配备中都少不了资深JavaScript应用程序开发者的角色.本书旨在帮助人们了解如何构建易于扩展和维护的完整JavaScript应用. 本书并不打算向读者详细讲解JavaScript语言基础,它基于你现有的JavaScript知识结构,向你展示那些会让你的编码工作长久受益的Ja

JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型_基础知识

ECMAScript是一种动态类型的语言,构建于5种简单数据类型(Undefined.Null.Boolean.Number.String)和一种复杂数据类型(Object)的基础之上.这篇文章就来复习一下简单数据类型,我会尽量从编程实践的角度来描述,下面代码运行环境为FireFox 14.0.1. 简单数据类型 简单数据类型 取值 Undefined undefined(只有一个值) Null null(只有一个值) Boolean true|false(只有两个值) Number 数值 St

javascript面向对象程序设计高级特性经典教程(值得收藏)_javascript技巧

本文实例讲述了javascript面向对象程序设计的高级特性.分享给大家供大家参考,具体如下: 1.创建对象的三种方式: 第一种构造法:new  Object var a = new Object(); a.x = 1, a.y = 2; 第二种构造法:对象直接量 var b = { x : 1, y : 2 }; 第三种构造法:定义类型 function Point(x, y){ this.x = x; this.y = y; } var p = new Point(1,2); 2.访问对象

JavaScript高级程序设计(第3版)学习笔记9 js函数(下)_基础知识

再接着看函数--具有魔幻色彩的对象. 9.作为值的函数 在一般的编程语言中,如果要将函数作为值来使用,需要使用类似函数指针或者代理的方式来实现,但是在ECMAScript中,函数是一种对象,拥有一般对象具有的所有特征,除了函数可以有自己的属性和方法外,还可以做为一个引用类型的值去使用,实际上我们前面的例子中已经有过将函数作为一个对象属性的值,又比如函数也可以作为另一个函数的参数或者返回值,异步处理中的回调函数就是一个典型的用法. 复制代码 代码如下: var name = 'linjisong'

JavaScript高级程序设计(第3版)学习笔记8 js函数(中)_基础知识

6.执行环境和作用域 (1)执行环境(execution context):所有的JavaScript代码都运行在一个执行环境中,当控制权转移至JavaScript的可执行代码时,就进入了一个执行环境.活动的执行环境从逻辑上形成了一个栈,全局执行环境永远是这个栈的栈底元素,栈顶元素就是当前正在运行的执行环境.每一个函数都有自己的执行环境,当执行流进入一个函数时,会将这个函数的执行环境压入栈顶,函数执行完之后再将这个执行环境弹出,控制权返回给之前的执行环境. (2)变量对象(variable ob

JavaScript高级程序设计(第3版)学习笔记7 js函数(上)_基础知识

变量类型 在说函数之前,先来说说变量类型. 1.变量:变量在本质上就是命名的内存空间. 2.变量的数据类型:就是指变量可以存储的值的数据类型,比如Number类型.Boolean类型.Object类型等,在ECMAScript中,变量的数据类型是动态的,可以在运行时改变变量的数据类型. 3.变量类型:是指变量本身的类型,在ECMAScript中,变量类型就只有两种:值类型和引用类型.当变量的数据类型是简单数据类型时,变量类型就是值类型,当变量的数据类型是对象类型时,变量类型就是引用类型.在不引起

JavaScript高级程序设计(第3版)学习笔记6 初识js对象_基础知识

在房子里面可以放你想放的任意事物--如果你有足够的美学造诣,你甚至可以弄一个房中房试试--当然,为了方便管理,我们会给房子里存放的所有事物都会取上一个不重复的名字,比如医药房间里的各种药品名称.在ECMAScript中,你可以在对象中存放任意你想放的数据,同样,我们需要给存放的数据取一个名字--也就是对象的属性名,再存放各种数据.再看看ECMA-262中对象的定义:无序属性的集合,其属性可以包含简单数据类型值.对象或者函数. 进入对象,我开始有些激动了,说实话,让我想起做这系列学习笔记的最初原因

关于《javascript 高级程序设计》里“稳妥构造函数模式“的一点疑问

问题描述 关于<javascript 高级程序设计>里"稳妥构造函数模式"的一点疑问 在<javascript 高级程序设计>第六章6.2.7提到"稳妥构造函数模式"的稳妥对象,指的是没有公共属性,而且其方法也不引用this 的对象,最适合在一些安全的环境中(这些环境中会禁止使用this 和new),或者在防止数据被其他应用程序(如Mashup程序)改动时使用.书中举例如下: function Person(name, age, job){

JavaScript高级程序设计笔记 事件冒泡和事件捕获

原文:JavaScript高级程序设计笔记 事件冒泡和事件捕获 1.事件冒泡 要理解事件冒泡,就得先知道事件流.事件流描述的是从页面接收事件的顺序,比如如下的代码: <body> <div> click me! </div> </body> 如果在body和div内都注册了click的事件监听,之后又点击了div区域,是body先响应还是div先响应?有意思的是,当时的浏览器开发团队IE和Netscape提出了差不多完全相反的事件流的概念.IE的事件流是事件