前端必备:从头开始,搞懂Promise

未来值

设想场景:你去汉堡店买汉堡,购买人数很多,无法立刻拿到汉堡。

当你付款完成后,就发出了对某个值(这里就是汉堡)的请求。此时店员就会给你一个东西代替汉堡,通常是带有编号的收据,那么收据上的编号就是你核销汉堡的凭证,这个编号也代表了汉堡店给你的承诺(promise),即,未来会给你一个汉堡。

此时有了收据,就可以等待(等待态)了,在等待的途中,你可以做其他的事情。

但是汉堡依旧在你的大脑中,你不会等到汉堡送来时产生“为什么给我个汉堡?”等其它疑惑,所以当汉堡送来时,你就会直接处理这个值(汉堡)——把它吃掉。

此时这个在大脑中的汉堡,你也可以理解为即将得到的汉堡,是一个“未来值”,即占住了位置,但并没有拿到实物进行处理,反而你正在做其他事。

等待片刻后,叫到了你的号码,你可以去领汉堡了。

此时会发生3种情况。

  1. 核对编号成功,完成交易,拿到汉堡。即,我需要的值(汉堡),已经处理好了,我拿承诺值(商家给的编号)换取这个值本身(汉堡)。此时,未来值成功了(得到汉堡了),结果就是你就开始吃汉堡了,吃饱了。

  2. 核对编号成功,汉堡卖完了。值(汉堡)没了,未来值(即将得到汉堡)失败了(汉堡并没得到),结果是你可能会换一个地方吃或者干别的。

  3. 商家系统故障,你的号永远都没被叫到。现实中有现实中的处理办法,但在程序中,这是一种未决议状态

从上面的例子可以看出,核对编号到拿到/未拿到汉堡到最终是吃还是没吃的结果,这是一个完整的过程,重要的是最后的结果,是吃了还是没吃。

这基本诠释了使用Promise的整个流程,即Promise先决议,然后确定未来值的状态,有成功也有失败,成功后对应一种结果返回,失败后对应一种结果返回,且只会有一种结果被返回

未决议状态会放在之后讨论。

Promise

Promise:从语义上可以看出,它是一个承诺,承诺一段时间后给你反馈一个结果,从语法上,它是一个对象,使用new来创建,它会有三种状态,等待pending、成功resolve、失败rejecte,且一旦状态确定,就无法更改,此时它成了不变值

Promise创建的任务是微任务。

未决议状态会放在之后讨论,它不是主观触发的一种状态,而以上三种,是promise必备的状态。

此时你是否想到未来值,它也有成功/失败的状态。

所以说:Promise会很好的展现未来值的特性,是一种封装和组合未来值的易于复用的机制。

来看看Promise的使用语法。

let p1 = new Promise((resolve, reject) => {
      // resolve("成功");
         reject("拒绝");
        })

使用决议函数reject()表示失败(请求拒绝)。

使用决议函数resolve()表示成功。

注意,这里为了一次展示语法也为了代码能正常执行,我将resolve(“成功”)注释掉了,因为状态一旦确定就无法更改,如果没有注释,那意思就是,先成功,后又改为失败,这样是不行的,只能有一个状态存在,所以将其中一个注释掉。

Promise内封装了“等待底层值的完成或拒绝”的状态,这个状态依赖于时间,所以是这个状态与时间有关,而promise本身与时间无关,可以得出:Promise可以按照可预测的方式进行组合,不用担心时序带来的变化或底层的结果。这可以避免很多传统异步的问题,之后我们会详细讨论。

同样的,Promise的状态不可更改会带来一些好处:

使用Promise决议过的值是不变值,外部无法进行更改,那么,将这个值传给第三方,或者多方进行观察,它就更加安全了,因为无法被修改。

由于状态不可更改,导致Promise产生的任务有以下特点:单一、不可逆、不可撤销,所以,一个Promise,不能有两种状态赋予。

单独的Promise展现了未来值的特性,但是,就像核销编号完成后拿到/未拿到汉堡所产生的结果例如:吃汉堡或换家店一样,Promise完成之后,会有一个东西来执行后面的事情,然后返回一些东西。

使用then()方法来执行得到成功/失败状态后的事情。

Then()

then()方法就像是promise的配套组件,每一个promise都会有一个对应的then()

then()方法内有两个参数,即两个方法,分别接收resolve()和reject()传递过来的“信号”,收到成功状态的信号,就传给then()的第一个函数value,收到失败状态的信号,就传给第二个参数reason,这里使用箭头函数,你可以使用其它函数方法和命名。

    new Promise((resolve, reject) => {
            resolve("操作成功,这是业务1");
// reject("拒绝状态,这是拒绝的业务处理 ");

    })
      .then(
        value => {
          console.log("成功业务处理 1");
        },
        reason => {
          console.log("拒绝的业务处理");
        }
      )

 这里注释掉了reject(),保留了resolve状态,所以传递到then()时就会执行value,输出“成功业务处理1”。

注意:promise对象有几个参数,就要给then()几个参数,即使是null。

一般是两个参数。

new Promise((resolve, reject) => {
            resolve("操作成功,这是业务1");
// reject("拒绝状态,这是拒绝的业务处理 ");

    })
.then(
      msg => {
        console.log("success:" + msg);
      },null)

这里对于reject状态并不想处理,所以没有处理方法,使用null,但不能没有,会报错。

没有null:

Promise不仅可以用于异步问题,还能用于很多地方,这些稍后会说,现在先考虑promise最基本的方法。

链式Promise

在正式开始说链式Promise之前,我们需要搞清楚两个概念。

  1. 每个then()都是一个Promise对象。

  2. 每个then()会优先处理离自己最近的那个promise。

先来看看第一点。

let p1 = new Promise((resolve, reject) => {
      reject("rejected");
    });
    let p2 = p1
      .then(
        value => console.log(value),
        reason => console.log(reason)
      )
      console.log(p2)

其中p2就是p1的then(),将它打印出来。

可以看到,它是一个准备态的promise。

对它的操作,要么就把它当作一个准备好的微任务并放入任务列表中,要么就将它看作一个promise,为它再配套一个then(),来对这个then()产生的结果再次进行处理。

let p1 = new Promise((resolve, reject) => {
      reject("rejected");
    });
    let p2 = p1
      .then(
        value => console.log(value),
        reason => console.log(reason)
      )
      .then(//.then对上一个promise进行处理,即p1.then
        a => console.log("成功"),
        b => console.log(b)
      );

第二个then()就在处理第一个then()了,可以看下运行结果。

let p1 = new Promise((resolve, reject) => {
      //resolve("fulfilled");
      reject("rejected");
    });
    let p2 = p1
      .then(
        value => console.log(value),
        reason => console.log(reason)
      )
      .then(//.then对上一个promise进行处理,即p1.then
        a => console.log("成功"),
        b => console.log("失败")
      );

注意:两个then()之间不能插入任何的东西。

你觉得输出的结果会是什么?

先看下浏览器的结果,与你的理解可能会有偏差。

你会不会觉得第二个输出,应该是“失败”?为什么会是成功?不是reject从上到下传过来的吗?

注意:第二个then()是对上一个then()进行了处理,我们对现在的p2,也就是第一个then()进行输出,看下它的状态。

注意:由于宏任务,微任务,同步任务的关系,我们设置一个定时器来让输出语句在微任务之后进行,才能看到微任务执行后的结果。

let p1 = new Promise((resolve, reject) => {
      //resolve("fulfilled");
      reject("rejected");
    });
    let p2 = p1
      .then(
        value => console.log(value),
        reason => console.log(reason)
      )
      .then(//.then对上一个promise进行处理,即p1.then
        a => console.log("成功"),
        b => console.log(b)
      );

    setTimeout(() => {
        console.log(p2);
    });

可以看到p2的状态是“fulfilled”,也就是成功了,所以在第二个then()中,执行了a,输出“成功”。

原因:第二个then()处理的是第一个then(),第一个then()接收到起始promise的信号,并处理了它,它的处理过程是很成功的,所以它是成功的,它的状态与起始promise无关,所以在接下来的第二个then()处理它时,是按照成功的状态走的,所以执行成功。

那有没有什么办法,让我们自定义传给第二个then()的promise的状态。

当然可以。但是并不是简单的使用then()一直往下串,我们还是需要创建新的promise对象来重新赋予任务状态。

剩下的内容会尽快更新,敬请期待~~

 omise((resolvereject=> {

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_42309926/article/details/108449142