Promise的核心机制

这是我参与更文挑战的第13天,活动详情查看: 更文挑战

一般情况下,用户代码主要用两种方法得到一个promise对象:

  1. 使用 new Promise来创建一个promise;

  2. 使用类方法 Promise.xxx()–包括resolve(),reject,all或者race等来获得一个promise;

任何方法得到的promise对象都具有then、catch等方法,也称为 promise.prototype.xxx()原型方法。
javascript约定调用这些方法讲‘绝对’不会跑出异常,而这也是得到一个新的promise对象的第三种方法:

  1. 使用原型方法promise.prototype.xxx() — promise.then、catch和finally等将返回一个新的promise。并且,任何一种方法都是立即得到promise对象的。

promise构造方法

const executor = function (resolve, reject) {}
new Promise(executor);
复制代码

executor是用户定义的执行函数。当js引擎通过new运算创建promise对象时,它事实上会在调用executor()之前就创建好一个新的promise对象的实例,并且得到关联给该实例的两个置值器:resolve和reject,接下来,他会调用executor,并且将resolve与reject作为入口参数传入,而executor函数会被执行直到退出。整个过程看起来像是让用户代码回调js引擎,

new Promise((resolve, reject) => {
    resolve(100);
});
复制代码

注意:当试图用自身来置值,js会抛出个异常

var delayResolve;
p = new Promise((resolve, reject) => {
    delayResolve = resolve;
});
delayResolve(p);  // TypeError: Chaining cycle detected for promise ...
复制代码

但是js并不检测交叉的循环引用的resolve置值器

// 尝试 resolve 自身
var delayResolve;
p = new Promise((resolve, reject) => {
    delayResolve = resolve;
});
// 将resolve暂存以完成上述实例
var delayResolve2;
p2 = new Promise((resolve, reject) => {
    delayResolve2 = resolve;
});
// 循环引用
delayResolve(p2);
delayResolve2(p);
复制代码

Then链中promise的置值逻辑

一个 prosmie可能会被置入两种值之一,这两种值是指:

  1. 如果promise被成功resolve,则该值为有效值(value)。
  2. 如果promise被主动reject或resolve失败,则该值用于记录原因(reason)。

且无论value还是reason都可以是js的任意数据类型。

p = new Promise((resolve, reject) => {
    try{
        resolve(x)
    }catch(e) {
        reject(e);
    }
});
// 下面是第二种抛出异常的方式
p = new Promise((resolve, reject) => {
    if (!ok) throw new Error();
    resolve(x);
});
复制代码

在Then链中,产生 reject 值的方式有两种,一种是通过抛出异常来使js引擎捕获异常对象,另一种是通过Promise.reject来显式地返回。前者是将错误对象作为值,后者得到一个不确定类型的值,它可以是任意的js数据。

Then链对值的传递以及catch处理

这里还存在一种最为特殊的情况:如果promise的resolve并没有关联有效的onFulfilled、onRejected呢?又或者,promise2根本就没有任何一个onFuifiied、onReject的响应函数呢?这两个问题的答案是简单而一直的:如果没有有效的响应函数,仍将产生新的promise2,并且它的resolve将以then链中当前的promise的值为值,因此完成的置值逻辑如下:

promise2 = p.then(resolved, rejected);
 // 它的完整逻辑如下
 try{
     if (isRejected(p)) {
         if(!isValidHandler(rejected)) throw result;
         x2 = rejected(result);
     } else {
         x2 = isValidHandler(resolved) ? resolved(result):result;
     }
     resolve(x2)
 }catch(e) {
     reject(e)
 }
 
 // 检测如下
 // 得到一个promise
 p = Promise.resolve(100);
 
 // 通过Then链得到promise2,但 onFulFilled、onRejected都未传入
 promise2 = p.then();
 
 // 由于没有函数来相应onFulfilled、onRejected,所以pomise2将默认使用p所代理的值
 promise2.then(console.log);
 
 // 类似的,这一置值过程也及时了将catch用作then链结尾的用法
 // 得到一个rejected的promise,使用定制的对象
 p = Promise.reject({message: 'REJECTED'});
 
 // 在then链中将用到响应函数
 resolved = x => x;
 rejected = obj => console.log(obj.message);
 
 // 通过then链得到promise3
 promise3 = p.then(resolved).catch(rejected);
复制代码

在任意场的then链中,如果链的前端出现了rejected值,无论经过多少级,then()响应,最终在rejected值都能持续向后传递并被‘链尾的catch’响应到。这也带来了promise机制的js中应用的第一原则。
始于promise,终于 catch。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享