Promise就像薛定谔的猫

1,674 阅读3分钟

Promise就像薛定谔的猫

突然觉得Promise和薛定谔的猫有相似之处。

  • 薛定谔的猫在密闭容器里,外面不清楚它的生死,只有打开盒子才知道。
  • 一个Promise对象,外面不知道到它的状态,只有用then/catch方法才能知道。

薛定谔的猫:是指将一只猫关在装有少量镭和氰化物的密闭容器里。镭的衰变存在几率,如果镭发生衰变,会触发机关打碎装有氰化物的瓶子,猫就会死;如果镭不发生衰变,猫就存活。根据量子力学理论,由于放射性的镭处于衰变和没有衰变两种状态的叠加,猫就理应处于死猫和活猫的叠加状态。

MDN上Promise对象的定义:Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。

我们不考虑量子力学那玄妙的理论,单是引用将猫咪放入密闭盒子这个情景。猫咪初始状态是待定状态(pending)——生与死的叠加态。在某一个时刻变成塌缩成已兑现(fulfilled)状态——生,或者已拒绝(rejected)状态——死。

而在盒子外的我们,并不知道盒子里猫咪的状态,需要通过then/catch方法才能知道。

决定猫咪生死

接下来,我们进入关猫咪的盒子内部,此时我们就成了上帝,可以用resolve和reject控制猫咪的生死。

// 构造器接受一个名为"executor function"的函数。这个函数拥有了控制猫咪生死的权力。
new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('活');
  }, 300);
});

这里,我们把制造一个Promise当成盒子内部的事,使用一个Promise对象当初盒子外部的事。分清了这两个视角,有助于我们理解Promise。

查看猫咪生死

我们先得到一个盒子(得到一个promise对象)。

// 从构造器得到
const promiseA = new Promise(...);
// 或者从原生api中得到
const promiseB = fetch(url);
// 或者从他人封装的方法得到
const promiseB = ajax(url);

我们需要一个方法,跟盒子联通起来,无论猫咪生死,都让我们知道。

// 通过then方法,它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
promiseA
    .then(()=> {
        // 跟猫咪玩耍
    }, () => {
        // 给猫咪安葬
    })

这样我们就放心了,无论猫咪怎样,我们都可以及时做出处理。

连接装猫的盒子

Promise的一大特性就是链式调用。then() 函数会返回一个和原来不同的新的 Promise。

const promise = playWithCat();
const promiseNew = promise.then(successCallback, failureCallback);

利用链式调用,连续执行两个或者多个异步操作

playWithCat().then(function(result) {
    // 再把猫放一个新盒子里
    return playWithCatAgian(result);
})
.then(function(newResult) {
    // 再把猫放一个新盒子里
    return playWithCatThird(newResult);
})
.then(function(finalResult) {
   // 累了,让猫歇会
})
.catch(failureCallback);

then 里的参数是可选的,catch(failureCallback) 是 then(null, failureCallback) 的缩略形式。

链式调用很好的解决了回调地狱:

playWithCat(function(result) {
  playWithCatAgian(result, function(newResult) {
    playWithCatThird(newResult, function(finalResult) {
        // 累了,让猫歇会
    }, failureCallback);
  }, failureCallback);
}, failureCallback);

小结

Promise的其他方法如Promise.all() 和 Promise.race() 。都可以类比成猫咪和盒子的故事。希望这样的类比可以让你更有效的理解Promise。加油共同学习吧。