promise对象作用域作为异步任务结果的占位符。它代表了一个暂时没有获得的值,但是未来有可能获得的值。基于这一点原因,在一个promise对象的整个生命周期中,它会经历多种状态。一个promise对象从等待(pending)状态开始,此时我们对承诺的值一无所知。因此一个等待状态的promise对象也称为未实现(unresolved)的promise。在程序执行的过程中,如果promise的resolve函数被调用,promise就会进入完成(fulfilled)状态,在该状态下我们能够获得承若的值。
console.log('----------仔细研究promsie的执行顺序---------------');
console.log('at code start');
//调用Promise构造函数来立即调用传入的参数
var ninjaDelayedPromise = new Promise((resolve, reject) => {
console.log('ninjaDelayedPromise executor.');
//在500ms之后,为promise调用resolve方法表明承若已经成功完成
setTimeout(()=>{
console.log('resolving ninjaDelayedPromise');
resolve('Hattori');
}, 500);
});
if (ninjaDelayedPromise != null) {
console.log('After creating ninjaDelayedPromise.');
}
//Promise的then方法用于创建一个当承诺兑现后执行的回调函数,在上述代码中当计时器超时会被执行
ninjaDelayedPromise.then(ninja=>{
if (ninja === 'Hattori') {
console.log('ninjaDelayedPromise resolve handled with Hattori');
}
});
//创建一个新的Promsie对象并立刻调用resolve函数
const ninjaImmeduatePromise = new Promise((resolve, reject) => {
console.log('ninjaImmediatePromise executor. Immediate resolve.');
resolve('Yoshi');
});
//创建一个回调函数,当promise调用resolve方法后执行,但我们的promise已经调用过resolve方法了
ninjaImmeduatePromise.then(ninja => {
if (ninja === 'Yoshi') {
console.log('ninjaImmediatePromise resolve handled with Yoshi');
}
});
console.log('at code end!');
从输出log看出,当打印日志'At code start'开始,通过使用console.log(),将信息输出至屏幕,从而我们能够轻易地跟踪函数的执行过程。下一步则通过调用Promise构造函数创建了一个新的Promise对象。它会立即调用执行函数并建立一个计数器。
//在500ms之后,为promise调用resolve方法表明承若已经成功完成
setTimeout(()=>{
console.log('resolving ninjaDelayedPromise');
resolve('Hattori');
}, 500);
计时器会在500ms之后调用promsie的resolve方法。这里可以是任何异步任务,简单起见这里选择了定时器。
在ninjaDelayedPromise被创建后,依然无法得知最终会得到什么值,或者无法保证promise会成功进入完成状态。(记住,它会一直等待计时器到时后调用resolve函数)。所以在构造函数调用后,ninjaDelayedPromise就进入了promise的第一个状态——等待状态。然后调用ninjaDelayedPromise的then方法,用于建立一个预计在promise被成功实现后执行的回调函数:
//Promise的then方法用于创建一个当承诺兑现后执行的回调函数,在上述代码中当计时器超时会被执行
ninjaDelayedPromise.then(ninja=>{
if (ninja === 'Hattori') {
console.log('ninjaDelayedPromise resolve handled with Hattori');
}
});
这个回调函数总会被异步调用,无论promise当前是什么状态。我们继续创建另一个promise——ninjaImmediatePromise,它会在对象构造阶段立刻调用promise的resolve函数,立即完成承诺。不同于ninjaDelayedPromise对象在构造后进入等待状态,ninjaImmediatePromise对象在解决状态下完成了对象的构造,所以该promsie对象就已经获得了Yoshi。
然后,通过调用ninjaImmeduatePromise的then方法,我们为其注册了一个回调函数。用于在promise成功被解决后调用。然而此时promise已经被解决了,难道这意味着这个成功回调函数被立即调用,或者被忽略吗?答案是两者都不。
Promise是设计用来处理异步任务的,所以JavaScript引擎经常会凭借异步处理使promise的行为得以预见。JavaScript通过在本次时间循环中的所有代码都执行完毕后,调用then回调函数处理promise。因此,从上述log可以看出,我们会看到首先是日志“At code end”,然后我们记录了ninjaImmediatePromise已经被解决。最后,经过500ms,ninjaDelayedPromise也被解决,从而响应的回调函数被调用。
拒绝Promise
拒绝一个promise有两种方式:显示拒绝,即在一个promise的执行函数中调用传入的reject方法;隐式拒绝,正处理一个promise的过程中抛出了一个异常。
console.log('----------------显示拒绝promise---------------------');
//可以通过调用传入的reject函数显式拒绝该promise。
const promise = new Promise((resolve, reject) => {
reject("Explicitly reject a promise!");
});
//如果promise被拒绝,则第二个回调函数error将会被调用!
promise.then(() => {
console.log('Happy path, will not be called!');},
error => {
console.log("A promise was explicitly rejected!");
}
);
通过调用传入的reject函数可以显示拒绝promise:reject("Explicitly reject a promise!");如果promise被拒绝,则第二个回调函数error总会被调用。
除此之外可以使用替代语法来处理拒绝promise,通过使用内置的catch方法。
console.log('-----------------------------链式调用catch方法-----------------------');
var promise = new Promise((resolve, reject) => {
reject('Explicitly reject a promise!');
});
//不同于应用第二个回调函数error,我们可以对catch方法进行链式调用,并将其传入回调函数error中。最终的结束条件相同。
promise.then(
()=>{
console.log('Happy path, will not be called!');
}
).catch(
()=>{
console.log("Promise was also rejected!");
}
);
通过在then方法后链式调用catch方法,我们同样可以在promise进入被拒绝状态时为其提供错误回调函数。在上述代码中,是否采用这种方式完全基于个人习惯。这两种方式的作用相同。
如果在执行过程中遇到了一个异常,除了显示拒绝(通过调用reject),promise还可以被隐式拒绝。
console.log('------------------------异常隐式拒绝一个promise--------------');
//如果在处理promise时出现未处理的异常,则会被隐式地拒绝
const promise = new Promise((resolve, reject) =>{
undeclaredVariable++;
});
//如果发生了异常,第二个回调函数error将被调用。
promise.then(
() => {
console.log('Happy path,will not be called!');
}
).catch(error =>{
console.log('Third promise was also rejected!');
});
在promise函数体内,我们试着对变量undeclaredVariable进行自增,该变量并未在程序在程序中定义。不出所料,程序会产生一个异常。由于在执行函数中没有try-catch语句,所以当前的promise被隐式拒绝了,catch回调函数最后被调用。在这种情况下,如果我们把错误回调函数作为then函数的第二个参数,结果也是相同的。
//如果在处理promise时出现未处理的异常,则会被隐式地拒绝
const promise = new Promise((resolve, reject) =>{
undeclaredVariable++;
});
//如果发生了异常,第二个回调函数error将被调用。
promise.then(
() => {
console.log('Happy path,will not be called!');
},
error=>{
console.log('error..............now');
}
).catch(error =>{
console.log('Third promise was also rejected!');
});
以这种方式处理promise中发生的错误可以说是相当简便。无论promise是被如何拒绝的,显示调用reject方法还是隐式调用,只要发生了异常,所有错误和拒绝原因都会在拒绝回调函数中被定位。
参考《JavaScript忍者秘籍》