大话Promise系列之一:借钱的故事

老姚
老姚 发布于 2016-11-17 20:01:46 浏览:2175 类型:原创 - 随笔 分类:JavaScript - 我也来说说系列 二维码: 作者原创 版权保护
看了两本书相关书籍后,准备写几篇笔记。
望读者要求别太高,就当乐呵看。emoticon
参考的书籍是:
1.http://es6.ruanyifeng.com/#docs/promise
2.http://liubin.org/promises-book/
3.《你不知道的JavaScript中卷》、《英文版》

本文是第一篇。
主要串一串promise相关api。
全文以借钱的故事来大话promise。

0.故事基本场景
一天,小红准备向小明借点钱。
小红给小明发个短信,说能否借我500元。
小明收到短信后,马上回复说,我知道了。
情况一、小明看了一下支付宝余额,回复小红说,钱打给你了。
情况二、小明看了一下支付宝余额,回复小红说,我也没钱了,你找别人吧。

上面就是故事背景,看我如何跟promise关联上。
1.小明收到短信后,马上回复对方,其实就是给对方一个承诺。
我知道这个事情了,你可以忙你的了。
此承诺就是promise。

2.小红求人家办事,不管人家办没办成,
只要对方给出最终结果(借了或没借),就是表示此事办完了。
事情办完,就表示该承诺已经决议。
而办成了(借了),就是表示该承诺已经完成。
没办成(没借),就表示该承诺已经拒绝。
而小明等待对方告诉自己结果的过程,就是表示该承诺待定。

而待定、完成、拒绝就是promise的三个状态。
而决议就是指从待定到完成或者从待定到拒绝这个状态变更。

3.不管对方借没借,最后小红都会有所响应。
如果小明借了,真高兴,这朋友还不错,当作备胎吧。
如果小明没借,小红会合计,穷屌丝,以后还是离他远点吧。

1.promise的hello world
至此可以敲敲代码了。
<script>
var account = 1000;
var p = new Promise(function(resolve, reject) {
	if (account >= 500) {
		resolve(500);
	} else {
		reject(new Error('no money'));
	}
});
p.then(function(value) {
	alert(value + ', good boy!');
}, function(error) {
	alert('bye bye');
});
</script>

其中Promise是构造函数,生成实例需要new。
而构造函数的参数需要一个函数,而该函数又需要两个参数,是两个回调函数。
该函数的内部实现,其实是如何决议的实现,
有钱,我就告诉对方,事情办成了,钱给你,调用的是完成回调(resolve),
没钱,我就告诉对方,事情没办成,调用的是拒绝回调(reject)。
Promise实例p上面同then方法注册完成回调和拒绝回调的业务处理逻辑。
上面就是最简单的promise使用案例了。

2.决议时,可以只有完成,没有拒绝的情形,或反之
假如小明是高富帅,小明永远不会拒绝,那么小红永远不会拜拜。
<script>
var p = new Promise(function(resolve, reject) {
	resolve(500);
});
p.then(function(value) {
	alert(value + ', good boy!');
}, function(error) {
	alert('bye bye');
});
</script>

对应这种promise的情形,有便捷写法:
<script>
var p = Promise.resolve(500);
p.then(function(value) {
	alert(value + ', good boy!');
}, function(error) {
	alert('bye bye');
});
</script>

对应直接拒绝同样也有类似的写法:
<script>
var p = Promise.reject(new Error('no money'));
p.then(function(value) {
	alert(value + ', good boy!');
}, function(error) {
	alert('bye bye');
});
</script>


3.决议可以是异步的

现实可能是,小明确实没钱,不过他没有马上拒绝,而是等了两个小时后,才装模作样回小红说,
“我没有,恰好我那几个哥们也没有”。
小红会觉得,这孩子还可以,留着不拉黑了。
<script>
var p = new Promise(function(resolve, reject) {
	setTimeout(function() {
		reject(new Error('no money'));
	}, 2000)
});
p.then(function(value) {
	alert(value + ', good boy!');
}, function(error) {
	alert('keep in touch...');
});
</script>

这里得提醒一下读者,promise模式主要就是解决异步问题。因为决议的时机可能是异步的。

4.回调可以是多个
小红收到钱后,心情大好,对小明说了谢谢,然后又去买了零食。
<script>
var account = 1000;
var p = new Promise(function(resolve, reject) {
	if (account >= 500) {
		setTimeout(function() {
			resolve(500);
		}, 300);
	} else {
		reject(new Error('no money'));
	}
});
p.then(function(value) {
	alert(value + ', good boy!');
});
p.then(function(value) {
	alert('go getting food');
});
</script>

上面的then函数调用时,没有传递第二个拒绝回调。
对应reject回调,除了使用then方法以外,还有单独的api,即catch。
<script>
var p = new Promise(function(resolve, reject) {
	setTimeout(function() {
		reject(new Error('no money'));
	}, 200)
});
p.catch(function(error) {
	alert('keep in touch...');
});
</script>


5.then和catch方法返回的也是个promise实例
小红向小明借钱时,小明给个承诺,此书小红心里这样想,等我谢完小明后,一定要犒劳自己。
其实,这是小红对自己一个承诺,对应的代码为:
<script>
var account = 1000;
var p = new Promise(function(resolve, reject) {
	if (account >= 500) {
		setTimeout(function() {
			resolve(500);
		}, 300);
	} else {
		reject(new Error('no money'));
	}
});
var p2 = p.then(function(value) {
	alert(value + ', good boy!');
	return value;
});
p2.then(function(value) {
	alert(value + ', go getting food');
});
</script>

p调用then后,返回的是一个新的promise实例,该实例决议的结果是通过return来实现的。

6.promise链
上面的代码中,我们发现p2变量是中间变量,可以去除,形成连缀语法:
<script>
var account = 1000;
var p = new Promise(function(resolve, reject) {
	if (account >= 500) {
		setTimeout(function() {
			resolve(500);
		}, 300);
	} else {
		reject(new Error('no money'));
	}
});
p.then(function(value) {
	alert(value + ', good boy!');
	return value;
}).then(function(value) {
	alert(value + ', go getting food');
});
</script>


7.promise的嵌套
借钱的故事的结局可能是这样的,小明确实没钱,不过他哥们小亮有,小亮借给他,他再借给小红。
<script>
var p = new Promise(function(resolve, reject) {	
	resolve(new Promise(function(res, rej) {
		res(500);
	}));
});
p.then(function(value) {
	alert(value + ', good boy!');
	return value;
}).then(function(value) {
	alert(value + ', go getting food');
});
</script>

首先resolve函数的参数可以是一个决议结果值,也可以是另外一个promise(小亮的承诺)。其实不只是promise只要对象有then方法即可。

8.then和catch方法也可以返回promise对象
故事的还有另外一种情况,小红心想如果没接到钱,那么就管妈妈要300元(妈妈给的承诺),然后再去买吃的。哼!男人靠不住!
<script>
var p = new Promise(function(resolve, reject) {	
	reject();
});
p.catch(function(value) {
	return Promise.resolve(300);
}).then(function(value) {
	alert(value + ', go getting food');
});
</script>


9.all方法
小红准备把iphone6换成7,可惜手里没多少钱,她想能否借到6000元,此时,她打开了qq找几个男生借借。
<script>
// 小明有闲钱1000
var p1 = new Promise(function(res, rej) {
	res(1000);
});

// 小山墨迹半天拿出500
var p2 = new Promise(function(res) {
	setTimeout(function() {
		res(500);
	}, 200);
});

// 小峰高富帅拿了3000
var p3 = Promise.resolve(3000);

// 前男友小光拿出了1000
var p4 = Promise.resolve(1000);

// 小智知小红乃绿婊,直接拒绝
var p5 = Promise.reject('no').catch(function() {return 0});

var p = Promise.all([p1, p2, p3, p4, p5]);
p.then(function(results) {
	var sum = results.reduce(function(a, b) { return a + b });
	return sum
}).then(function(sum) {
	alert(sum);
});
</script>

all方法传进promise实例数组,返回一个promise实例。
数组中的实例都完成,那么状态即为完成状态,得到完成值的数组。
不然只会得到第一拒绝值。

10.race方法
另一个版本的故事,小红想换iphone7,分别对三个人说,
“要是有男朋友就好了,这样他可以给我买了。”。
结果有人上套了,
<script>
// 小明犹豫了一下,说如果没人给你买我给你买
var p1 = new Promise(function(res, rej) {
	setTimeout(function() {
		res('小明');
	}, 400)
});

// 小山最后才表态
var p2 = new Promise(function(res, rej) {
	setTimeout(function() {
		res('小山');
	}, 500)
});

// 小峰先说我给你买吧
var p3 = new Promise(function(res, rej) {
	setTimeout(function() {
		res('小峰');
	}, 200)
});


var p = Promise.race([p1, p2, p3]);
p.then(function(who) {
	alert(who);
});
</script>

race方法是看哪个先决议(完成或拒绝),就返回哪个决议值。
这个故事告诉我们,女生搞撒网策略还是明智的。

总结
本文通过借钱小故事穿插得用到了promise的基本api。
1.Promise构造函数
2.Promise.prototype.then
3.Promise.prototype.catch
4.Promise.resolve
5.Promise.reject
6.Promise.all
7.Promise.run
基本上算是蜻蜓点水吧,希望给不了解promise的同学,一个入门的机会而已。
个人来说,当然还有后续文章,谢谢关注。emoticon

本文完。

z
给个赞 44 人点赞
收藏 26 人收藏
评论 已有 29 条评论;以下用户言论只代表其个人观点,不代表 前端网(QDFuns) 的观点或立场。
登录 以后才能发表评论
最新评论
booogle
booogle2016-12-19 16:42:3329F
写的很详细,很好理解。
举报 支持 (0) 回复 (0)
老姚
老姚2016-11-25 14:20:4628F
es6支持,是原生的,当然也有各种库。 //@小单纯:Promise 是原生js提供的吗? 不是第三方吧。
举报 支持 (0) 回复 (0)
milko
milko2016-11-22 14:29:5027F
赞一个,写的很浅显易懂,看其他的博客都没太看懂
举报 支持 (0) 回复 (0)
小单纯
小单纯2016-11-22 11:09:1726F
Promise 是原生js提供的吗? 不是第三方吧。
举报 支持 (0) 回复 (1)
老姚
老姚2016-11-21 16:13:1325F
恩,2那块我重新命名了。 //@台灯油条:"2. "那里好像有点笔误。小红,这个绿茶。
举报 支持 (0) 回复 (0)
陈陈陈大文
陈陈陈大文2016-11-19 08:51:5424F
文笔不错,哈哈
举报 支持 (0) 回复 (0)
台灯油条
台灯油条2016-11-19 07:12:1023F
"2. "那里好像有点笔误。小红,这个绿茶。
举报 支持 (0) 回复 (1)
hugeannex
hugeannex2016-11-18 15:57:3322F
把个鬼啊,回头学习学习。。。 //@老姚:恩,谢谢,回头帮我把把关。 //@hugeannex:上班忙,没空看。感觉不错,赞了再说。有空回头看。。。。
举报 支持 (0) 回复 (0)
Nick-chen
Nick-chen2016-11-18 15:29:2021F
姚大哥不错,写的浅显易懂,有张鑫旭的风格
举报 支持 (0) 回复 (0)
mano
mano2016-11-18 14:44:3120F
知道哪里错了。明白了。 //@mano展开代码
<script>
var p = new Promise(function(resolve, reject) {	
	var _p = new Promise(function(res, rej) {
		//哥们拒绝了,并回应 是不是去泡妞啊  
		//这个不能让女孩子知道吧
		//因此小明应该针对朋友的反馈进行美化 再给小红 
		reject(new Error('小子,是不是泡妞去啊'));
	});
	//这里美化
_p.then(function(value) {
	 resolve(500)
},function(error){
    reject(new Error("朋友取海外了,联系不上。"));
});

});
p.then(function(value) {
	alert(value + ', good boy!');
	 
},function(error){
    alert(error);
    
});
</script>

但是他这个直接把朋友的返回处理了,咋整
举报 支持 (0) 回复 (0)
mano
mano2016-11-18 14:40:3819F
展开代码
<script>
var p = new Promise(function(resolve, reject) {	
	var _p = new Promise(function(res, rej) {
		//哥们拒绝了,并回应 是不是去泡妞啊  
		//这个不能让女孩子知道吧
		//因此小明应该针对朋友的反馈进行美化 再给小红 
		reject(new Error('小子,是不是泡妞去啊'));
	});
	//这里美化
_p.then(function(value) {
	 resolve(500)
},function(error){
    reject(new Error("朋友取海外了,联系不上。"));
});

});
p.then(function(value) {
	alert(value + ', good boy!');
	 
},function(error){
    alert(error);
    
});
</script>

但是他这个直接把朋友的返回处理了,咋整
举报 支持 (0) 回复 (1)
Mr豆花
Mr豆花2016-11-18 12:47:4818F
写的真的是很好啊。这几天刚好在学es6,感觉看了姚哥(不,桃哥,不对,是猴哥)的这篇文章后对promise的理解深刻多了。
举报 支持 (0) 回复 (0)
545841598
5458415982016-11-18 12:13:2617F
emoticon //@老姚:桃哥。。。也许叫猴哥更好,毕竟猴子吃桃子emoticon //@545841598:桃哥就是狠emoticon
举报 支持 (0) 回复 (0)
分界线
分界线2016-11-18 11:18:1215F
先赞再看好习惯
举报 支持 (0) 回复 (0)
分界线
分界线2016-11-18 11:18:1216F
先赞再看好习惯
举报 支持 (0) 回复 (0)
老姚 老姚 作者

与自己为敌,与自己为友,一边深挖思想,一边埋葬自己。

作者最新