文档章节

初识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从简单变复杂了,作者从另一个角度看待这个问题。 原文: JavaScript’s a mess – and that’s a good thing 译者: Fundebug 为了保证可读性,本文采用意译而非直译。另外...

Fundebug
07/03
0
0
JavaScript 一团乱,这是好事

译者按: JavaScript从简单变复杂了,作者从另一个角度看待这个问题。 原文: JavaScript’s a mess – and that’s a good thing 译者: Fundebug 为了保证可读性,本文采用意译而非直译。另外...

a独家记忆
07/18
0
0
异步JavaScript与Promise

异步? 我在很多地方都看到过异步(Asynchronous)这个词,但在我还不是很理解这个概念的时候,却发现自己常常会被当做“已经很清楚”(* ̄ロ ̄)。 如果你也有类似的情况,没关系,搜索一下这个...

银月光海
2015/02/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

apache顶级项目(二) - B~C

apache顶级项目(二) - B~C https://www.apache.org/ Bahir Apache Bahir provides extensions to multiple distributed analytic platforms, extending their reach with a diversity of s......

晨猫
今天
1
0
day152-2018-11-19-英语流利阅读

“超级食物”竟然是营销噱头? Daniel 2018-11-19 1.今日导读 近几年来,超级食物 superfoods 开始逐渐走红。不难发现,越来越多的轻食餐厅也在不断推出以超级食物为主打食材的健康料理,像是...

飞鱼说编程
今天
7
0
SpringBoot源码:启动过程分析(二)

接着上篇继续分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 一样的,我们先把时序图贴上来,方便理解: 二.源码分析 回顾一下,前面我们分析到了下...

Jacktanger
昨天
3
0
Apache防盗链配置,Directory访问控制,FilesMatch进行访问控制

防盗链配置 通过限制referer来实现防盗链的功能 配置前,使用curl -e 指定referer [root@test-a test-webroot]# curl -e "http://www.test.com/1.html" -x127.0.0.1:80 "www.test.com/1.jpg......

野雪球
昨天
5
0
RxJava threading

因为Rx针对异步系统设计,并且Rx也自然支持多线程,所以新的Rx开发人员有时会假设Rx默认是多线程的。在其他任何事情之前,重要的是澄清Rx默认是单线程的。 除非另有说明,否则每次调用onNex...

woshixin
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部