读完此文对promise一定会有新的认识。
- promise有三种状态:
pending(进行中)、fulfilled(已成功)和rejected(已失败);- promise状态改变只有两种可能:从
pending变为fulfilled和从pending变为rejected。状态一旦改变,就不会再变;- 为了方便描述,一般将
fulfilled状态称为resolved。
resolve(value):如果当前是pending,则变为resolved:const p1 = new Promise((resolve, reject) => {
resolve('success');
});
console.log(p1); // Promise {: 'success'}
reject(reason):如果当前是pending,则变为rejected:const p2 = new Promise((resolve, reject) => {
reject('err');
});
console.log(p2); // Promise {: 'err'}
pending,则变为rejected:const p3 = new Promise((resolve, reject) => {
throw new Error('err');
});
console,.log(p3) // Promise {: Error: err
总结:改变promise的状态有三种方式(调用resolve、调用reject和抛出异常)。
const p = new Promise((resolve, reject) => {
resolve('success');
});
p.then((value) => {
console.log('value1:', value);
});
p.then((value) => {
console.log('value2:', value);
});
p.then((value) => {
console.log('value3:', value);
});
/* 执行结果:
value1: success
value2: success
value3: success
*/
const p = new Promise((resolve, reject) => {
reject('err');
});
p.then(
(value) => {},
(reason) => {
console.log('reason:1', reason);
},
);
p.then(
(value) => {},
(reason) => {
console.log('reason:2', reason);
},
);
p.then(
(value) => {},
(reason) => {
console.log('reason:3', reason);
},
);
/* 执行结果:
reason:1 err
reason:2 err
reason:3 err
*/
总结:一个promise同时指定多个成功/失败回调函数,当promise改变为对应的状态时都会调用。
我们知道promise在状态改变时会调用对应的回调函数,但在不同的情况下两种还是有先后顺序的。
const p = new Promise((resolve, reject) => {
// 执行异步任务,这里用setTimeout模拟,实际上可以是ajax请求
setTimeout(() => {
resolve('success'); // 2. 后改变状态(同时指定数据),异步执行回调函数
}, 1000);
});
p.then((value) => { // 1. 先指定回调函数,保存当前指定的回调函数(代码底层)
console.log('value:', value);
});
const p = new Promise((resolve, reject) => {
resolve('success'); // 1. 先改变状态(同时指定数据)
});
p.then((value) => { // 2. 后指定回调函数,异步执行回调函数
console.log('value:', value);
});
或者:
const p = new Promise((resolve, reject) => {
// 执行异步任务,这里用setTimeout模拟,实际上可以是ajax请求
setTimeout(() => {
resolve('success'); // 1. 先改变状态(同时指定数据)
}, 1000);
});
setTimeout(() => {
p.then((value) => { // 2. 后指定回调函数,异步执行回调函数
console.log('value:', value);
});
}, 1001); // 时间比上面晚一点即可
总结:
我们知道promise是支持链式调用的,比如下面的情况:
const p = new Promise((resolve, reject) => {
resolve('success');
});
p.then(
(value) => {
console.log('value1:', value);
},
(reason) => {
console.log('reason1:', reason);
},
)
.then(
(value) => {
console.log('value2:', value);
},
(reason) => {
console.log('reason2:', reason);
},
)
.then(
(value) => {
console.log('value3:', value);
},
(reason) => {
console.log('reason3:', reason);
},
);
/* 执行结果:
value1: success
value2: undefined
value3: undefined
/*
为什么后面两个回调的执行结果是undefined呢,因为新的promise的结果状态是由then()指定的回调函数执行的结果决定的。可以看到第一个then方法中回调函数没有指定返回值,那么就会默认返回undefined,从而导致后面的then方法的回调函数的执行结果都为undefined。
那要想后面两个then方法的回调函数的执行结果有值,可以做如下修改:
p.then(
(value) => {
console.log('value1:', value);
+ return 'hello';
},
(reason) => {
console.log('reason1:', reason);
},
)
.then(
(value) => {
console.log('value2:', value);
+ return Promise.resolve('world');
},
(reason) => {
console.log('reason2:', reason);
},
)
.then(
(value) => {
console.log('value3:', value);
},
(reason) => {
console.log('reason3:', reason);
},
);
/* 执行结果:
value1: success
value2: hello
value3: world
/*
体会一下下面代码的输出结果:
const p = new Promise((resolve, reject) => {
reject('err');
});
p.then(
(value) => {
console.log('value1:', value);
return 'hello';
},
(reason) => {
console.log('reason1:', reason);
throw 'err2';
},
)
.then(
(value) => {
console.log('value2:', value);
return Promise.resolve('world');
},
(reason) => {
console.log('reason2:', reason);
return 1000;
},
)
.then(
(value) => {
console.log('value3:', value);
},
(reason) => {
console.log('reason3:', reason);
},
);
/* 执行结果:
reason1: err
reason2: err2
value3: 1000
*
总结:新的promise(记为promise1)的结果状态:
then()指定的回调函数执行的结果决定。异常:promise1变为rejected ,reason的值为抛出的异常;非promise的任意值:promise1变为resolved ,value的值为返回的任意值;新的promise:此promise的结果就会成为promise1的结果。promise.then()会返回一个新的promise,可以写成then()的链式调用;then()的链式调用来串联多个同步/异步任务。看下面这段代码:
new Promise((resolve, reject) => {
// 模拟异步任务
setTimeout(() => {
console.log('执行任务1(这是异步的)');
resolve(100);
}, 1000);
})
.then((value) => {
console.log('任务1的返回结果:', value);
console.log('执行任务2(这是同步的)');
return Promise.resolve(200);
})
.then((value) => {
console.log('任务2的返回结果:', value);
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('执行任务3(这是异步的)');
resolve(300);
}, 1000);
});
})
.then((value) => {
console.log('任务3的返回结果:', value);
});
/* 执行结果:
执行任务1(这是异步的)
任务1的返回结果: 100
执行任务2(这是同步的)
任务2的返回结果: 200
执行任务3(这是异步的)
任务3的返回结果: 300
*/
可以看到3个任务不论同步还是异步,都是按顺序执行的。
需要注意的是:若想在then()中继续执行异步任务,则用promise包装,在其中调用新promise的resolve方法来讲值传递出去。
new Promise((resolve, reject) => {
reject('err');
})
.then((value) => {
console.log('value1:', value);
})
.then((value) => {
console.log('value2:', value);
})
.then((value) => {
console.log('value3:', value);
})
.catch((reason) => {
console.log('reason:', reason);
});
/* 执行结果:
reason: err
*/
上面的这段代码其实相当于:
new Promise((resolve, reject) => {
reject('err');
})
.then(
(value) => {
console.log('value1:', value);
},
(reason) => {
throw reason;
},
)
.then(
(value) => {
console.log('value2:', value);
},
(reason) => {
throw reason;
},
)
.then(
(value) => {
console.log('value3:', value);
},
(reason) => {
throw reason;
},
)
.catch((reason) => {
console.log('reason:', reason);
});
reason会逐级往下传递,直到最后的catch。
当使用promise.then链式调用时,若在中间过程中断,后面的then方法就不会再调用。
new Promise((resolve, reject) => {
reject('err');
})
.then((value) => {
console.log('value1:', value);
})
.then(
(value) => {
console.log('value2:', value);
},
(reason) => {
return new Promise(() => {});
},
)
.then((value) => {
console.log('value3:', value);
})
.catch((reason) => {
console.log('reason:', reason);
});
上面的代码最后没有任何输出。由于在第二个then方法的rejected回调中返回了一个pending状态的promise对象,因此后续的then方法也就不会再执行了。