说说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实例进行使用:
var promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
之后再异步操作执行完之后,根据resolve
或者reject
进行处理,catch操作可以代替第二个function处理error的情况。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
Promise如果直接跟一堆then,就会直接执行下去,如果中间有异步函数,那么效果同样可能会是还没来得及执行完就到了下一个then的内容。
我们可以看一下以下例子:
const config = require('./config.json');
const fs = require('fs');
console.log(config.path.temp);
// 判断文件是否存在,存在则删除
//
const existDir = function() {
return new Promise((resolve, reject) => {
fs.exists(config.path.temp, (exists) => {
resolve(exists);
});
})
};
existDir()
.then((value) => {
console.log(value);
})
.then((value) => {
if (!value) {
fs.mkdir('111', (err)=> {
if (!err) {
console.log('success');
return '1';
} else {
throw Error('something wrong');
}
})
}
})
.then((value) => {
console.log(value);
});
在此例中返回值为:
false
undefined
success
可以看出,先输出了第三个console.log,最后输出mkdir后的结果。
但是如果then链返回的是Promise对象,就会按照顺序依次执行。前一个的resolve返回值是后一个函数中的value。
当我们要一次执行多个Promise(非链式调用),可以使用Promise.all
,它的特点是如果一个失败了,那么就执行Promise的回调函数,这样就不适用于全部都执行完再做判断的场合,如果需要,我想到的一个方法是全部都使用resolve,根据resolve传出的参数决定判断与否,但是这样其实丧失了一定的语义特征。
接下来的第二种情况也就是Promise的链式调用,也是我们过去回调地狱的情况——如果A执行完要执行B,B执行完要执行C,怎么办。
一种常见的方法是Generator+Promise,优点是语义清晰,完全跟同步逻辑一致,一目了然。
function getFoo () {
return new Promise(function (resolve, reject){
resolve('foo');
});
}
var g = function* () {
try {
var foo = yield getFoo();
console.log(foo);
} catch (e) {
console.log(e);
}
};
function run (generator) {
var it = generator();
function go(result) {
if (result.done) return result.value;
return result.value.then(function (value) {
return go(it.next(value));
}, function (error) {
return go(it.throw(error));
});
}
go(it.next());
}
run(g);
以上实例来自阮一峰的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函数)。
当然,我还是觉得,所有东西应该为逻辑的清晰服务,怎么清晰怎么来吧。
植入部分
如果您觉得文章不错,可以通过赞助支持我。
如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。