转: 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,那么我们就可以做到像同步函数那样的异常捕获了。

时间: 2024-08-08 03:16:37

转: Promises与Javascript异步编程的相关文章

深入解析Javascript异步编程

这里深入探讨下Javascript的异步编程技术.(P.S. 本文较长,请准备好瓜子可乐 :D) 一. Javascript异步编程简介 至少在语言级别上,Javascript是单线程的,因此异步编程对其尤为重要. 拿nodejs来说,外壳是一层js语言,这是用户操作的层面,在这个层次上它是单线程运行的,也就是说我们不能像Java.Python这类语言在语言级别使用多线程能力.取而代之的是,nodejs编程中大量使用了异步编程技术,这是为了高效使用硬件,同时也可以不造成同步阻塞.不过nodejs

JavaScript 异步编程

JavaScript 异步编程 第一章 深入理解JavaScript事件 1. javascirpt一般是单线程执行,setTimeout 和 setInterval 仅当cpu空闲时执行. var start = new Date; setTimeout(function(){ var end = new Date; console.log('Time elapsed:', end - start, 'ms'); }, 500); while (new Date - start < 1000)

探索Javascript异步编程

异步编程带来的问题在客户端Javascript中并不明显,但随着服务器端Javascript越来越广的被使用,大量的异步IO操作使得该问题变得明显.许多不同的方法都可以解决这个问题,本文讨论了一些方法,但并不深入.大家需要根据自己的情况选择一个适于自己的方法. 笔者在之前的一片博客中简单的讨论了Python和Javascript的异同,其实作为一种编程语言Javascript的异步编程是一个非常值得讨论的有趣话题. JavaScript 异步编程简介 回调函数和异步执行 所谓的异步指的是函数的调

JavaScript异步编程设计快速响应的网络应用

JavaScript已然成为了多媒体.多任务.多内核网络世界中的一种单线程语言.其利用事件模型处理异步触发任务的行为成就了JavaScript作为开发语言的利器.如何深入理解和掌握JavaScript异步编程变得尤为重要!!!<JavaScript异步编程设计快速响应的网络应用>提供了一些方法和灵感. 一.深入理解JavaScript事件 1. 事件的调度 JavaScript事件处理器在线程空闲之前不会运行(空闲时运行). var start = new Date(); setTimeout

JavaScript异步编程(一) 深入理解JavaScript事件

JavaScript异步编程 深入理解JavaScript事件 ?事件的调度 JavaScript事件处理器在线程空闲之前不会运行 线程的阻塞 var start = new Date(); // setTimeout和setInterval的计时精度比期望值差 setTimeout(function(){ var end = new Date(); console.log('Time elapsed', end - start, 'ms'); }, 500); while(new Date -

JavaScript异步编程(2)- 先驱者:jsDeferred

原文出处: linkFly   欢迎分享原创到伯乐头条 JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascript的异步编程,jsDeferred也是有必要探索的:因为Promise/A+规范的制定基本上是奠定在jsDeferred上,它是javascript异步编程中里程碑式的作品.jsDeferred自身的实现也是非常有意思的. 本文将探讨项目js

Javascript异步编程方法之------“事件监听”

Javascript异步编程方法之------“事件监听”另一种思路是采用事件驱动模式.任务的执行不取决于代码的顺序,而取决于某个事件是否发生.还是以f1和f2为例.首先,为f1绑定一个事件(这里采用的jQuery的写法).f1.on('done', f2);上面这行代码的意思是,当f1发生done事件,就执行f2.然后,对f1进行改写:function f1(){setTimeout(function () {// f1的任务代码f1.trigger('done');}, 1000);}f1.

Javascript异步编程方法之------“发布/订阅”

Javascript异步编程方法之------“发布/订阅”我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行.这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern).这个模式有多种实现

5分种让你了解javascript异步编程的前世今生,从onclick到await/async

javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为浏览器设计的GUI编程语言,GUI编程的特性之一是保证UI线程一定不能阻塞,否则体验不佳,甚至界面卡死. 一般安卓开发,会有一个界面线程,一个后台线程,保证界面的流畅.由于javascript是单线程,所以采用异步非阻塞的编程模式,javascript的绝大多数api都是异步api. 本文是本人的一个