javascript深入研究promise

60 篇文章 0 订阅
55 篇文章 1 订阅

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忍者秘籍》

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值