文档章节

初识JavaScript Promises

梵高
 梵高
发布于 2014/06/29 22:50
字数 1166
阅读 2906
收藏 98

JavaScript有很多槽点,嵌套回调怕是千夫所指。

很久之前,我一直使用async来处理JavaScript异步编程中的嵌套回调问题。当然我也大概的了解过一些其它旨在解决这些问题的类库,诸如EventProxy、Jscex、StepJS、thenjs。

当我第一次看到Promises规范的时候,我根本无法理解它所带来的好处。譬如每个初次学习Promises的人都见过如下的示例代码:

//callbacks 
function callback(err, value){ 	
    if(err){ 		
        // do something 		
        return; 	
    } 	
    //do other things     with value 
} 
//Promises 
promise.then(function(value){ 	
    //do something with value 
}, function(err){ 	
    //do other things with error 
})

很难相信上面的代码会让人对Promises刮目相看。不过正如bluebird作者Petka所说,上面的代码是 “最不诚实的比较”。所以我恳请你把类似的代码从你的记忆中擦出吧。

不妨让我们再回到async的讨论上。async的问题在于它不能优雅地应对需求的变化,一旦业务逻辑有较大的变化,代码结构会进行大幅度的调整,而Promises却能够轻松的应对这种变化。待时机适宜我会进行详细的比较,首先让我们开始快速地了解Promises。


Promises是什么

Promises象征着一个异步操作的最终结果。Promises交互主要通过它的then方法,then方法接受一个回调函数,这个回调函数接受执行成功的返回值或执行失败的错误原因,错误原因一般是Error对象。需要注意的是,then方法执行的返回值是一个Promise对象,而then方法接受的回调函数的返回值则可以是任意的JavaScript对象,包括Promises。基于这种机制,Promise对象的链式调用就起作用了。

Promises的状态

Promise对象有三种状态:pending(初始状态)、fulfilled(成功执行)、rejected(执行出错)。pending状态的Promise对象可以转换到其它两种状态。


上面的文本不够形象,不妨上些代码来加深对Promises的认识。

注:由于主流的JavaScript环境(包括NodeJS)对Promises/A+标准的实现不太令人满意,我的示例均使用了第三方类库bluebird

var fs = require('fs')
var Promise = require('bluebird')
//改造fs.readFile为Promise版本
var readFileAsync = function(path){
    //返回一个Promise对象,初始状态pending
    return new Promise(function(fulfill, reject){
	fs.readFile(path,  'utf8', function(err, content){
		//由pending状态进入rejected状态
		if(err)return reject(err)
		//由pending状态进入fulfilled状态
		return fulfill(content)
	})
})
}

//开始使用,调用其then方法,回调接受执行成功的返回值
readFileAsync('./promise-1.js').then(function(content){
console.log(content)
})

看了上面的代码以后,是不是觉得Promises其实并不复杂呢。

OK,我们继续延续上面的代码,来简单比较一下传统回调和Promises的使用上的差别: /* * 简单比较一下传统方式和Promises方式 * 需求:读取两个文件并打印内容 * */

 //callbacks
fs.readFile('./promise-1.js', 'utf8', function(err, content1){
	//嵌套一次
	console.log('#', content1)
	fs.readFile('./promise-1.js', 'utf8', function(err, content2){
 		//第二次嵌套
		console.log('##', content2)
	})
})

//Promises
readFileAsync('./promise-1.js').then(function(content1){
	console.log('#', content1)
	//这里返回一个Promise对象
	return readFileAsync('./promiscuitye-1.js')
}).then(function(content2){
	console.log('##', content2)
})

上面的代码都没有错误处理,这是一个后果很严重的坏习惯。不过今天我们的重点不在这里,而是分析上下两段代码的主要区别。

第一段代码是传统的嵌套回调,在第二次打印的时候已经使用了两次缩进,而Promises链式调用then方法成功地避免了一次缩进(嵌套),维持了代码结构的相对平坦。上面的代码略显简陋,如果再加上错误处理,Promises毫无疑问将会大放光彩,有兴趣请关注后续章节。

本章写到这里就结束了,相信大家已经对Promises的有了一个初步认识。规范文档往往很难理解,我没有过多的描述规范,因为我相信代码最能够解释一切。不过对规范文档有兴趣的可以自行阅读参考链接。

最后我想强调的一点就是:Promises这种维持代码结构平坦的魔力在业务逻辑复杂多变的情况下是非常有用的

参考链接


未完待续(2014-06-28 00:59)

© 著作权归作者所有

共有 人打赏支持
梵高
粉丝 21
博文 20
码字总数 6905
作品 0
深圳
程序员
私信 提问
加载中

评论(15)

梵高
梵高

引用来自“luwenhua”的评论

readFileAsync('./promise-1.js').then(function(content1){
console.log('#', content1)
//这里返回一个Promise对象
return readFileAsync('./promiscuitye-1.js')
}).then(function(content2){
console.log('##', content2)
})
请问,看上去第一个读文件会阻塞第二个,是这样么?
其实这里谈不上阻塞,只是例子是先读取第一个文件然后读取第二个文件。 只要不使用同步方法,是不会阻塞的。
luwenhua
luwenhua
readFileAsync('./promise-1.js').then(function(content1){
console.log('#', content1)
//这里返回一个Promise对象
return readFileAsync('./promiscuitye-1.js')
}).then(function(content2){
console.log('##', content2)
})
请问,看上去第一个读文件会阻塞第二个,是这样么?
梵高
梵高

引用来自“撸蕉香的程猿序”的评论

//开始使用,调用其then方法,回调接受执行成功的返回值

readFileAsync('./promise-1.js').then(function(content){

console.log(content)

如何接受失败的回调函数呢
下一篇会讲到。后面计划还有三到五篇
码农与厨子
码农与厨子
//开始使用,调用其then方法,回调接受执行成功的返回值

readFileAsync('./promise-1.js').then(function(content){

console.log(content)

如何接受失败的回调函数呢
梵高
梵高

引用来自“webit”的评论

首先抱歉,我只看了你的文章的第一句话:“JavaScript有很多槽点,嵌套回调怕是千夫所指。”我不明白这两句有啥关系? 语言本身确实是“有很多槽点”,但是“嵌套回调”本身这个特性没问题吧? 就像一个工具,用得好不好更多的得看是谁用
嵌套回调被吐槽已经是不争的事实了吧。
梵高
梵高

引用来自“Angry_Snail”的评论

嵌套回调导致的代码可读性、可维护性、及变量作用域问题,谁用谁知道
对于Python程序员来说缩进超过5个就是耻辱!!

前端 AngularJS + $q
服务器 NodeJS + q

以上,不谢
Angry_Snail
Angry_Snail
嵌套回调导致的代码可读性、可维护性、及变量作用域问题,谁用谁知道
对于Python程序员来说缩进超过5个就是耻辱!!

前端 AngularJS + $q
服务器 NodeJS + q

以上,不谢
zqq90
zqq90
首先抱歉,我只看了你的文章的第一句话:“JavaScript有很多槽点,嵌套回调怕是千夫所指。”我不明白这两句有啥关系? 语言本身确实是“有很多槽点”,但是“嵌套回调”本身这个特性没问题吧? 就像一个工具,用得好不好更多的得看是谁用
灰花走湿
灰花走湿
https://www.promisejs.org/
梵高
梵高

引用来自“大头先生”的评论

提个文字用语的建议:

文中关于“Promise的状态”部分 -
“由于主流的JavaScript环境(包括NodeJS)对Promises/A+标准的实现差强人意,我的示例均使用了第三方类库bluebird。”

其中,“差强人意”的意思是“大体上令人满意”,用在原文这里不太合适
语文是体育老师教的,不好意思,已经修正
初识JavaScript Promises之二

初始JavaScript Promises之二 上一篇我们初步学习了JavaScript Promises,本篇将介绍Promise如何优雅地进行错误处理以及提升操作node.js风格1的异步方法的逼格,没错就是使用promisify2。 异...

梵高
2014/07/15
0
0
HTML 5视频教程系列之JavaScript学习篇-何韬-专题视频课程

HTML 5视频教程系列之JavaScript学习篇—52816人已学习 课程介绍 HTML 5视频教程系列中JavaScript开发的基础知识讲解及学习。 课程收益 通过自学视频掌握HTML 5开发手机应用和手机游戏的技能...

pkutao
2015/02/10
0
0
解读 JavaScript 之事件循环和异步编程

欢迎阅读专门探索 JavaScript 及其构建组件的系列文章的第四章。 在识别和描述核心元素的过程中,我们还分享了关于构建 SessionStack 时需要遵循的一些经验法则,一个 JavaScript 应用必须是...

oschina
2017/12/14
2.2K
6
JavaScript中Promise使用

定义 Promise对象用于包装异步函数执行结果,以便用同步的方式处理其结果。 promise 包含3种状态: pending: 初始状态 fulfilled: 完成状态 rejected: 失败状态 链式调用方法 then()返回一个...

王桥修道院副院长
01/12
0
0
[译]JavaScript: Promises 介绍及为何 Async/Await 最终取得胜利

原文地址:JavaScript: Promises and Why Async/Await Wins the Battle 异步函数在JavaScript中有好有坏。好的一面是异步函数是非阻塞的,因此很快 - 特别是在Node.js上下文中。缺点是处理异...

sunshine杨小咩
2018/09/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java并发编程基础(三)

线程间通信 线程间通信称为进程内通信,多个线程实现互斥访问共享资源时会互相发送信号货这等待信号,比如线程等待数据到来的通知,线程收到变量改变的信号。 线程阻塞(同步)和非阻塞(异步)...

chendom
9分钟前
1
0
阿里重磅开源首款自研科学计算引擎Mars,揭秘超大规模科学计算

日前,阿里巴巴正式对外发布了分布式科学计算引擎 Mars 的开源代码地址,开发者们可以在pypi上自主下载安装,或在Github上获取源代码并参与开发。 此前,早在2018年9月的杭州云栖大会上,阿里...

阿里云官方博客
18分钟前
1
0
我是怎样和Linux系统结缘并通过红帽RHCE认证的

我高考完当时就是选择的计算机科学与技术专业,上大学以后联想到的和计算机相关的就只有写代码,开发,网站,网页设计,就没有其他的了,当时学习写代码也都是在Windows上,什么C#、C++之类的...

问题终结者
28分钟前
1
0
SSH之端口转发

第一部分 概述 当你在咖啡馆享受免费 WiFi 的时候,有没有想到可能有人正在窃取你的密码及隐私信息?当实验室的防火墙阻止了你的网络应用端口,是不是有苦难言?来看看 SSH 的端口转发功能带...

无语年华
33分钟前
1
0
我是怎样和Linux系统结缘并通过红帽RHCE认证的

我高考完当时就是选择的计算机科学与技术专业,上大学以后联想到的和计算机相关的就只有写代码,开发,网站,网页设计,就没有其他的了,当时学习写代码也都是在Windows上,什么C#、C++之类的...

linuxprobe16
50分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部