初识JavaScript Promises
博客专区 > 梵高 的博客 > 博客详情
初识JavaScript Promises
梵高 发表于4年前
初识JavaScript Promises
  • 发表于 4年前
  • 阅读 2895
  • 收藏 99
  • 点赞 9
  • 评论 15

【腾讯云】新注册用户域名抢购1元起>>>   

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

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)

标签: promise promises
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 21
博文 20
码字总数 6905
评论 (15)
木川瓦兹
异步编程中的嵌套回调问题 能否举个例子
梵高

引用来自“CodingKu”的评论

异步编程中的嵌套回调问题 能否举个例子

后面会讲到的,谢谢关注0
金拱门

引用来自“币须网”的评论

引用来自“CodingKu”的评论

异步编程中的嵌套回调问题 能否举个例子

后面会讲到的,谢谢关注0
难道是 回调的数据 不是理想的结果?
大头先生
提个文字用语的建议:

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

其中,“差强人意”的意思是“大体上令人满意”,用在原文这里不太合适
梵高

引用来自“币须网”的评论

引用来自“CodingKu”的评论

异步编程中的嵌套回调问题 能否举个例子

后面会讲到的,谢谢关注0

引用来自“开源中国首席骨科主任”的评论

难道是 回调的数据 不是理想的结果?
不会,请关注后续章节哈。主要是不想把所有内容写在一篇文章里,读者读得累,我写得也累。 我还是喜欢这种又浅入深的姿势-_-。 Promises/A+规范其实并不复杂,但是只看规范很难体会到为什么要用Promises。我的方式就是大概解释下规范,抓住核心要点,然后上例子加强理解就可以了。
梵高

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

提个文字用语的建议:

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

其中,“差强人意”的意思是“大体上令人满意”,用在原文这里不太合适
语文是体育老师教的,不好意思,已经修正
灰花走湿
https://www.promisejs.org/
zqq90
首先抱歉,我只看了你的文章的第一句话:“JavaScript有很多槽点,嵌套回调怕是千夫所指。”我不明白这两句有啥关系? 语言本身确实是“有很多槽点”,但是“嵌套回调”本身这个特性没问题吧? 就像一个工具,用得好不好更多的得看是谁用
Angry_Snail
嵌套回调导致的代码可读性、可维护性、及变量作用域问题,谁用谁知道
对于Python程序员来说缩进超过5个就是耻辱!!

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

以上,不谢
梵高

引用来自“Angry_Snail”的评论

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

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

以上,不谢
梵高

引用来自“webit”的评论

首先抱歉,我只看了你的文章的第一句话:“JavaScript有很多槽点,嵌套回调怕是千夫所指。”我不明白这两句有啥关系? 语言本身确实是“有很多槽点”,但是“嵌套回调”本身这个特性没问题吧? 就像一个工具,用得好不好更多的得看是谁用
嵌套回调被吐槽已经是不争的事实了吧。
码农与厨子
//开始使用,调用其then方法,回调接受执行成功的返回值

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

console.log(content)

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

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

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

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

console.log(content)

如何接受失败的回调函数呢
下一篇会讲到。后面计划还有三到五篇
luwenhua
readFileAsync('./promise-1.js').then(function(content1){
console.log('#', content1)
//这里返回一个Promise对象
return readFileAsync('./promiscuitye-1.js')
}).then(function(content2){
console.log('##', content2)
})
请问,看上去第一个读文件会阻塞第二个,是这样么?
梵高

引用来自“luwenhua”的评论

readFileAsync('./promise-1.js').then(function(content1){
console.log('#', content1)
//这里返回一个Promise对象
return readFileAsync('./promiscuitye-1.js')
}).then(function(content2){
console.log('##', content2)
})
请问,看上去第一个读文件会阻塞第二个,是这样么?
其实这里谈不上阻塞,只是例子是先读取第一个文件然后读取第二个文件。 只要不使用同步方法,是不会阻塞的。
×
梵高
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: