说说Promise
标题不知道怎么拟定比较好,总之是讲Promise的吧,基本上算是第一次讲Promise,以前Rails+Angular的时候曾经说过,不过那个时候对于callback hell和Promise解决的东西理解的并不深刻,所以解释的也很肤浅(不明明这次依旧是肤浅的解释)。
首先……V8的Promise性能实在不靠谱,都没有第三方的快,bluebird有一篇性能比较(反正大致是想说自己快吧):http://bluebirdjs.com/docs/benchmarks.html
慢归慢,基本上一些对于性能需求不太迫切的项目还是可以用自带的Promise的,Node6对于ES6的支持已经相当全面了,这一点可以用npm install es-checker
检查一下。(毕竟回调地狱恶心到吐血)。
Promise其实并不是Javascript提出的一个概念,可以看这篇文章了解一下Promise A+的标准:http://cuipengfei.me/blog/2016/05/15/promise/
普通的对象经过封装之后就能变成Promise实例进行使用:
1var promise = new Promise(function(resolve, reject) {
2 // ... some code
3
4 if (/* 异步操作成功 */){
5 resolve(value);
6 } else {
7 reject(error);
8 }
9});
10
之后再异步操作执行完之后,根据resolve
或者reject
进行处理,catch操作可以代替第二个function处理error的情况。
1promise.then(function(value) {
2 // success
3}, function(error) {
4 // failure
5});
6
Promise如果直接跟一堆then,就会直接执行下去,如果中间有异步函数,那么效果同样可能会是还没来得及执行完就到了下一个then的内容。
我们可以看一下以下例子:
1const config = require('./config.json');
2const fs = require('fs');
3console.log(config.path.temp);
4
5// 判断文件是否存在,存在则删除
6//
7const existDir = function() {
8 return new Promise((resolve, reject) => {
9 fs.exists(config.path.temp, (exists) => {
10 resolve(exists);
11 });
12 })
13};
14
15existDir()
16.then((value) => {
17 console.log(value);
18})
19.then((value) => {
20 if (!value) {
21 fs.mkdir('111', (err)=> {
22 if (!err) {
23 console.log('success');
24 return '1';
25 } else {
26 throw Error('something wrong');
27 }
28 })
29 }
30})
31.then((value) => {
32 console.log(value);
33});
34
在此例中返回值为:
false
undefined
success
可以看出,先输出了第三个console.log,最后输出mkdir后的结果。
但是如果then链返回的是Promise对象,就会按照顺序依次执行。前一个的resolve返回值是后一个函数中的value。
当我们要一次执行多个Promise(非链式调用),可以使用Promise.all
,它的特点是如果一个失败了,那么就执行Promise的回调函数,这样就不适用于全部都执行完再做判断的场合,如果需要,我想到的一个方法是全部都使用resolve,根据resolve传出的参数决定判断与否,但是这样其实丧失了一定的语义特征。
接下来的第二种情况也就是Promise的链式调用,也是我们过去回调地狱的情况——如果A执行完要执行B,B执行完要执行C,怎么办。
一种常见的方法是Generator+Promise,优点是语义清晰,完全跟同步逻辑一致,一目了然。
1function getFoo () {
2 return new Promise(function (resolve, reject){
3 resolve('foo');
4 });
5}
6
7var g = function* () {
8 try {
9 var foo = yield getFoo();
10 console.log(foo);
11 } catch (e) {
12 console.log(e);
13 }
14};
15
16function run (generator) {
17 var it = generator();
18
19 function go(result) {
20 if (result.done) return result.value;
21
22 return result.value.then(function (value) {
23 return go(it.next(value));
24 }, function (error) {
25 return go(it.throw(error));
26 });
27 }
28
29 go(it.next());
30}
31
32run(g);
33
以上实例来自阮一峰的ES6教程,run函数是封装后的,如果不理解,可以先看看:Promise, generator, async與ES6里面有逐步分析流程。
当然,这种方式适用于模块之间的解耦,似乎对于一些相同模块异步函数而言比较浪费,不够友好,有些时候我们也不知道到底要重复几次。用yield反而很奇怪(除了yield的部分,Generator函数其他部分和一般函数无疑,可以把yield看作断点)。
此时我们可以直接用循环,或者reduce进行操作,可以看:http://www.kancloud.cn/kancloud/promises-book/44249
然而ES7中的async/await可以完美的取代Generator+Promise的复杂模式(毕竟要自己写一个run函数)。
当然,我还是觉得,所有东西应该为逻辑的清晰服务,怎么清晰怎么来吧。
评论 (0)