前言
JS中异步编程主要分为四种,其中回调和生成器不是这篇文章的重点,本文主要集中在Promise和async, await上面。
Promise
首先我们看Promise的几个特点:
- 回调函数延迟绑定即then方法,它可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个参数可选,一般使用catch触发,无论那种方式都是把回调函数延迟执行。
- 返回值穿透。
readFilePromise('1.json').then(data => {
return readFilePromise('2.json');
}).then(data => {
return readFilePromise('3.json');
}).then(data => {
return readFilePromise('4.json');
});
可以看到then方法返回的Promise可以在后面继续使用。
- 错误冒泡,整个thenable链式调用发生的每一处错误都可以由最后一个catch捕获。
then方法
then毫无疑问是这些方法种最重要的,我学习链式调用时下面代码解答了我很多疑惑。
注意then接收两个参数,都是函数,第二个可选。
同时函数返回的可以是一个值也可以是一个Promise,如果是前者,他会调用一个Promise包裹传递给后面使用;如果是后者同样也会调用给后面使用。
var p = new Promise(function(resolve, reject){
resolve(1);
});
p.then(function(value){ //第一个then
console.log(value);
return value*2;
}).then(function(value){ //第二个then
console.log(value);
}).then(function(value){ //第三个then
console.log(value);
return Promise.resolve('resolve');
}).then(function(value){ //第四个then
console.log(value);
return Promise.reject('reject');
}).then(function(value){ //第五个then
console.log('resolve: '+ value);
}, function(err){
console.log('reject: ' + err);
})
接着来看一段执行顺序的判断:
var p1 = new Promise( function(resolve,reject){
console.log('start1')
resolve( 1 );
});
p1.then(
function(value){
console.log('p1 then value: ' + value);
}
).then(
function(value){
console.log('p1 then then value: '+value);
}
);
var p2 = new Promise(function(resolve,reject){
resolve( 2 );
});
p2.then(
function(value){
console.log('p2 then value: ' + value);
}
).then(
function(value){
console.log('p2 then then value: ' + value);
}
).then(
function(value){
console.log('p2 then then then value: ' + value);
}
);
console.log('start2')
最后的执行结果为:
VM382:2 start1
VM382:33 start2
VM382:8 p1 then value: 1
VM382:22 p2 then value: 2
VM382:12 p1 then then value: undefined
VM382:26 p2 then then value: undefined
VM382:30 p2 then then then value: undefined
resolve和reject
关于resolve,它可以接受普通值,也可以接收一个Promise
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
如这一段程序,3000ms之前p1的状态是pendding,由于这是p2中resolve依赖p1的状态,所以p2的状态我们可以忽略了。
这时p2走then方法,result即为一个Promise,状态pendding。
3000ms后走catch,这是因为p1状态改变,而p2直接转发了p1的reject。
all和race
一个是都完成才算成功,一个是谁跑得快谁成功。
当然关于all和race还有一些细节,如传的是值而不是promise的话会先进行Promise处理;error若在Promise中声明,是不会走all的catch方法的等等。