我不知道Promise

我不知道Promise

Promise实例的创建
  • 使用new Promise();
  • 使用类方法Promise.XXX(),如:Promise.resolve()、Promise.reject()、Promise.all()、Promise.race()等;
  • 实例调用原型方法Promise.prototype.XXX(),如:.then()、.catch()、.finally();
  • 上述方法都是立即得到一个promise对象;
Promise核心过程
1、通过构造方法创建promise实例
const executor = function(resolve, reject) {
    ...
}
let promise1 = new Promise(executor);

上面代码中,executor是我们定义的执行器函数,引擎通过new运算创建promise对象时,会先创建好promise对象的实例,并得到关联给该实例的两个置值器:resolve()和reject(),再调用executor,并把两个置值器作为入口参数传入并立即执行,之后返回promise实例。

这里executor的所有返回值都会被忽略,我们只能通过两个置值器来改变promise对象(代理/绑定)的值,可以传入任何除了该promise实例的值。如果传入了自身则:

let outResolve;
let promise1 = new Promise((resolve, reject) => {
  outResolve = resolve;
});
outResolve(p); // TypeError: Chaining cycle detected for promise
2、没有延时

Promise机制中并没有时间维度,没有任何延时行为。在javascript中,不论使用原型方法、类方法、还是构造方法创建一个promise对象时,创建过程是立即完成的。只不过需要注意的是promise所代理的值是否就绪,如果就绪了,那么如promise1.then(func)中的func函数就会被执行了。

3、Then链

在javascript中,"Then链"就是两个promise对象之间顺序执行的关系。如:

let promise1 = new Promise((resolve, reject) => {
  resolve(100);
});
// 通过promise.then()来得到新的promise2
let promise2 = promise1.then(function foo() {
  ...
});

promise1.then()代表了对顺序逻辑的理解,同时也说明promise2与promise1两者所代理的数据之间是有关联的。上例中foo()函数其实是onFulfilled参数:

// .then()方法,上例中的foo()函数作为onFulfilled参数传入
let promise2 = promise1.then(onFulfilled, onRejected);
function onFulfilled(value) {
  ...
}
function onRejected(reason) {
  ...
}

当promise1的数据就绪(promise1对象绑定了值)时,引擎就将根据就绪状态触发onFulfilled/onRejected之一,并以该函数:

  • 退出时的返回值,或

  • 中止执行时的状态(如异常)

作为值来调用promise2的置值器。

因此从宏观上来看,是给“promise1绑定值”的行为(result ready就绪)触发了thenable行为。所谓“thenable行为”,就是调用then链的后续promise置值器,并在整个链上触发连锁的“thenable行为”。

promise1.then()也就是Promise.prototype.then原型方法主要做了三件事:

  • 创建新的promise2对象;
  • 登记promise1与promise2之间的关系;
  • 将onFulfilled、onRejected关联给promise2的resolve置值器,并确保promise1绑定的数据就绪时调用onFulfilled、onRejected;
4、Then链中promise2的置值逻辑

一个promise可能会被置入两种值:

  • resolve成功,则该值为有效值(value);

  • resolve失败(如异常)或主动reject,则该值用于记录原因(reason);

在构建promise的执行器中可以向resolve/reject传入任意javascript数据。

接下来如果promise1的Then链上有promise2,那么前面说的onFulfilled、onRejected就会被触发:

// 响应onFulfilled、onRejected的函数
const resolved = function(value){}
const rejected = function(reason){}
// Then链
let promise2 = promise1.then(resolved, rejected);

其中resolved/rejected响应的都是promise1的状态,它们只是promise2的置值前提。

向promise2置值逻辑伪代码:

// 伪代码(1)。对于代码:
// let promise2 = promise1.then(resolved, rejected);
// 来说,对象promise2将发生如下置值逻辑:
try{
  // the <result> proxy by <promise1>
  // result 是 promise1代理的值
  if(isRejected(promise1)){  // 如果promise1的状态为rejected,调用resolved, 反之调用rejected
   x2 = rejected(result); // call onRejected <result> as reason
  }else{
   x2 = resolved(result); // call onFulfilled <result> as value
  }
  resolve(x2); // 置值promise2
}catch(e){
  reject(e);   // 置值promise2
}

这里看到无论resolved/rejected返回何值,都调用promise2的resolve置值器绑定值。只有当"thenable行为执行异常时",才会调用promise2的reject置值器。

另外需注意"resolve a rejected promise"仍然会是一个reject值。所以,在Then链中,产生reject值的方法有两种,一种是如上抛异常;另一种是通过Promise.reject()显式的返回。如:

// 在Then链上reject一个promise
// 方法1
let promise2 = promise1.then(()=> {
    throw new Error();
});
// 方法2
let promise2 = promise1.then(()=> {
    return Promise.reject(reason)
})

这两种方法得到的reason不同:方法1得到一个错误对象作为reason值;方法2得到一个不确定类型的reason值来表示原因,它可以是任意javascript数据。

5、Then链对值的传递以及.catch()处理

有一种特殊情况:promise2的resolve没有关联有效的 onFulfilled、onRejected函数,或者根本就没有这些函数,那么仍会产生promise2实例,并且它的resolve将以Then链中当前promise(这里是promise1)的值为值,这又叫做值穿透。置值逻辑伪代码如下:

// 伪代码(2)。对于代码:
// let promise2 = promise1.then(resolved, rejected);
// 完整置值逻辑:
try{
  // the <result> proxy by <promise1>
  // result 是 promise1代理的值
  if(isRejected(promise1)){
   if(!isValidHandler(rejected)) throw result; // 将result做为reason
   x2 = rejected(result); 
  }else{
   x2 = isValidHandler(resolved) ? resolved(result) // 同 “伪代码(1)”
   : result; // 直接用promise1代理的数据
  }
  resolve(x2); // 置值promise2
}catch(e){
  reject(e);   // 置值promise2
}

检测如下:

// 得到一个promise
let p = Promise.resolve(100);
// 通过Then链得到promise2,不传入onFulfilled、onRejected
let promise2 = p.then();
// 由于没有函数响应onFulfilled、onRejected,所以promise2将默认使用p所代理的值
promise2.then(console.log);

类似地,这一置值过程也解释了将.catch()用作Then链结尾的用法:

// 得到一个rejected的promise
let p = Promise.reject('reject reason');
// p是rejected的,p.then调用中并没有传入rejected响应函数
let promise2 = p.then(x=>x);
// promise3是promise2使用.catch()作为链尾得到的一个promise
let promise3 = promise2.catch(console.log); // 'reject reason'

所以在任意长的Then链中,如果链的前端出现了rejected值,无论经过多少级.then()响应(只响应onFulfilled),最终该rejected值都能持续向后传递并被.catch()响应到。这也是Promise机制在javascript中应用的第一原则:始于promise,终于catch。确保链上任何可能的异常都得以处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值