Promise的兴起,是因为异步方法调用中,往往会出现回调函数一环扣一环的情况。这种情况导致了回调金字塔问题的出现。不仅代码写起来费劲又不美观,而且问题复杂的时候,阅读代码的人也难以理解。
例如:
db.save(data, function(data){
// do something...
db.save(data1, function(data){
// do something...
db.save(data2, function(data){
// do something...
done(data3); // 返回数据
})
});
});
- 假设有一个数据库保存操作,一次请求需要在三个表中保存三次数据。那么我们的代码就跟上面的代码相似了。这时候假设在第二个db.save出了问题怎么办?基于这个考虑,我们又需要在每一层回调中使用类似try...catch这样的逻辑。
- 另外一个缺点就是,假设我们的三次保存之间并没有前后依赖关系,我们仍然需要等待前面的函数执行完毕, 才能执行下一步,而无法三个保存并行,之后返回一个三个保存过后需要的结果。(或者说实现起来需要技巧)
ES6 Promise
Promise对象状态
它三个状态:
pending(执行中)
fulfilled(成功)
-
reject(拒绝)
状态转换关系为:pending->fulfilled,pending->rejected。
Promise的长相就像这样子:
var promise = new Promise(function func(resolve, reject){
// do somthing, maybe async
if (success){
return resolve(data);
} else {
return reject(data);
}
});
promise.then(function(data){
// do something... e.g
console.log(data);
}, function(err){
// deal the err.
})
这里的变量promise是Promise这个对象的实例。
promise对象在创建的时候会执行func函数中的逻辑。resolve这个回调会将值传递到一个特殊的地方。这个特殊的地方在哪呢?就是下面代码中的then,我们使用then中的回调函数来处理resolve后的结果。比如上面的代码中,我们将值简单的输出到控制台。如果有错误,则reject到then的第二个回调函数中,对错误进行处理。
Promise数据流动
promise的then方法依然能够返回一个Promise对象,这样我们就又能用下一个then来做一样的处理。
第一个then中的两个回调函数决定第一个then返回的是一个什么样的Promise对象。
假设第一个then的第一个回调没有返回一个Promise对象,那么第二个then的调用者还是原来的Promise对象,只不过其resolve的值变成了第一个then中第一个回调函数的返回值。
假设第一个then的第一个回调函数返回了一个Promise对象,那么第二个then的调用者变成了这个新的Promise对象,第二个then等待这个新的Promise对象resolve或者reject之后执行回调。
-
Promise对象还有一个方法catch,这个方法接受一个回调函数来处理错误。
promise.catch(function(err){ // deal the err. })
控制并发的Promise
Promise有一个”静态方法”——Promise.all(注意并非是promise.prototype), 这个方法接受一个元素是Promise对象的数组。
- 这个方法也返回一个Promise对象,如果数组中所有的Promise对象都resolve了,那么这些resolve的值将作为一个数组作为Promise.all这个方法的返回值的(Promise对象)的resolve值,之后可以被then方法处理。如果数组中任意的Promise被reject,那么该reject的值就是Promise.all方法的返回值的reject值.
还有一个和Promise.all相类似的方法Promise.race,它同样接收一个数组,只不过它只接受第一个被resolve的值。