目录

未来值

Promise

Then()

链式Promise

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

2. 是否在promise中return

3. 每个then()会处理离自己最近的那个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(“成功”)注释掉了,因为状态一旦确定就无法更改,如果没有注释,那意思就是,先成功,后又改为失败,这样是不行的,只能有一个状态存在,所以将其中一个注释掉。

使用new来创建的promsie是标准promise。

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. 是否在promise中return。

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

先来看看第一点。

1.每个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.thena => 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.thena => 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.thena => console.log("成功"),b => console.log(b));setTimeout(() => {console.log(p2);});

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

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

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

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

此时就要讨论第二点了,先看上个问题的解决办法。

2. 是否在promise中return

只需要在第一个then()当中新创建一个promise并且return它即可。

let p1 = new Promise((resolve, reject) => {resolve("fulfilled");}) .then(value => {return new Promise((resolve, reject) => {//只要return了,后面的then针对的就是这个return的新promise           reject("处理失败");})},reason => console.log(reason)).then(//此时的then是对上面的then的处理value => {console.log("成功:" + value);},reason => console.log("error" + reason));

在浏览器中查看结果。

起初的promise状态为resolve,所以执行value中的函数,value将新的promise返回,而这个新的promise的状态是reject,所以走到第二个then()中的reason(),打印出“erro处理失败”。

这个过程很像工厂的流水线,比如做面包,原料经过第一个机器,被做成面包胚,再经过第二个机器,被烤熟,最后的结果就是得到一个熟的面包,之前的原料和生面包胚都不复存在,没有人会在意它们,只会在意到手的面包。

但是,注意:第一个机器需要将面包胚吐出来,才能到下一个机器那里进行加工,这就是为什么要return这个promise的原因,我们需要将当前的promise进行返回,才能让下一个then()处理它。

有返回就有不返回,不返回会怎么样呢?

就像原料卡在机器里不出来一样,整个成产线都崩溃了,看看浏览器里的情况。

成功了是因为我们新建的promise并不影响整体流程,像之前说过的一样,经过一轮一轮then()的处理就行,那undefined呢?

Undefined和下一行错误息息相关,因为我们新建了promise却没有给它相对应的then(),所以这个promise是不能正常创建任务的,它什么都没有给下一个then(),但是它的状态是resolve(),所以是“成功:undefined”。

所以说,当你需要一步一步处理你的promise时,千万不要忘了return。

可是,并不总是需要处理标准的promise对象,就像一样的原料,我可以让它变成面包胚、披萨饼、或者其它的东西再传送出去一样,我们也可以返回其它的类型。

例如普通的对象和类。

先来看返回普通的对象。

let p1 = new Promise((resolve, reject) => {resolve("fulfilled");}).then(value => {return{//返回普通的对象name:"Cherrie"}},reason => {}).then(value => {console.log(value);console.dir(value);},reason => {console.log(reason);});

在浏览器里打印它。

对象就被返回出来了,你也可以使用它返回其他需要的类型,返回类,修改以上代码即可,这里不多赘述。

在这里强调它可以返回其它类型值的原因是,我们可以通过这个特点来返回除标准promise以外的其它类promise类型,也就是类似标准promise的promise类型,不是我们使用的class哦。

先看代码吧。

 .then(value => {return {then(resolve,reject){resolve("成功")}}},reason => {})

在这个then()中,我们返回一个对象,对象中有一个then()方法。

注意了,这个对象返回的可就不是普通对象了,它返回的是一个promise对象

放上完整的代码来验证一下。

let p1 = new Promise((resolve, reject) => {resolve("fulfilled");}).then(value => {return {then(resolve,reject){resolve("成功")}}},reason => {}).then(value => {console.log(value);},reason => {console.log(reason);});

在浏览器中查看结果。

看,此时的对象被下一个then()当作promise处理了,并且打印出了成功。

同样的,只要返回的对象中有这个then()方法,那么它就会被当作是一个promise处理。

你可以在类中,在静态方法中都使用它,然后,返回的值就会被当作promise处理了。

接下来,我们来看第三点。

3. 每个then()会处理离自己最近的那个promise

这个概念其实更像一个工具,用来配对我们的promise和then,因为,在promise的使用中,并不都是像以上的例子中那样,有十分明显的链式结构,我们也会出现嵌套,

  let p1 = new Promise((resolve, reject) => {resolve("fulfilled");}).then(value => {return new Promise((resolve,reject)=>{resolve("我是第一个promise的then中新创建的promise")}).then(value => {console.log("成功"+value);},reason => {console.log(reason);})},reason => {}).then(value => {console.log(value);},reason => {console.log(reason);});

这就是一种明显的嵌套情况,是不是看起来很乱,这时候就用到了我们所说的“每个then()会处理离自己最近的那个promise” 。

在p1的下的第一个then()当中,我们创建了新的promise并返回,但是,在这个新的promise下面,我们定义了then()。此时这个新promise,是谁在处理,它下面的then(),还是p1的第二个then()?

我们先看浏览器的返回结果。

很明显,它被新promise下定义的then()直接处理了,并没有像通常的return一样,把它返回给了p1的第二个then()进行处理,所以,p1的第二个then(),可以直接删掉。

  let p1 = new Promise((resolve, reject) => {resolve("fulfilled");}).then(value => {return new Promise((resolve,reject)=>{resolve("我是第一个promise的then中新创建的promise")}).then(value => {console.log("成功"+value);},reason => {console.log(reason);})},reason => {})

以上就是本篇的全部内容了,是promise的入门部分,这是系列文章,剩下的内容会另开篇幅更新。介时会在这里放上链接

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

omise((resolve, reject) => {

前端必备:从头开始,搞懂Promise之Promise基础相关推荐

  1. 音视频面试必备:一文搞懂视频相关的基础概念

    1.引言 随着移动互联网的普及,实时音视频技术已经在越来越多的场景下发挥重要作用,已经不再局限于IM中的实时视频聊天.实时视频会议这种功能,在远程医疗.远程教育.智能家居等等场景也司空见惯. 虽然实时 ...

  2. this指向_前端面试之彻底搞懂this指向

    this是JavaScript中的一个关键字,但是又一个相对比较特别的关键字,不像function.var.for.if这些关键字一样,可以很清楚的搞清楚它到底是如何使用的. this会在执行上下文中 ...

  3. 前端:一篇彻底搞懂vuex (mapState、mapGetters、mapMutations、mapActions)

    文章目录 一.state 1.1 state使用 1.2 mapState 辅助函数 二.getters 2.1 getters的使用 三.Mutation 3.1 mutations的使用 3.2 ...

  4. 从头开始搞懂 MySQL(07)为什么同一条 SQL 时快时慢

    1.为什么 SQL 会变慢 在我们平时工作的时候,有时候会发现,同一条 SQL 语句,在正常执行的时候特别快,但有时候不知道为什么,它就会变慢,并且这样的场景很难复现.是什么导致了 SQL 语句变慢了 ...

  5. 每天搞懂10道Java基础题day06

    题一 1.如下的Java程序 public class Test { public static void main(String[] args) { System.out.println(args[ ...

  6. 帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

    帮你彻底搞懂JS中的prototype.__proto__与constructor(图解) 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文 ...

  7. 这一篇彻底搞懂JS中的prototype、__proto__与constructor真的很好

    文章目录 1. 前言 2. _ _ proto _ _ 属性 3. prototype属性 4. constructor属性 5. 总结 提示:不要排斥,静下心来,认真读完,你就搞懂了!(可以先看一下 ...

  8. (转)帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)

    文章目录 1. 前言 2. _ _ proto _ _ 属性 3. prototype属性 4. constructor属性 5. 总结 提示:不要排斥,静下心来,认真读完,你就搞懂了!(可以先看一下 ...

  9. 丁奇mysql45讲百度云下载_MySQL实战45讲,丁奇带你搞懂MySQL【完结】

    开篇词.这一次,让我们一起来搞懂MySQL.mp3 开篇词.这一次,让我们一起来搞懂MySQL.pdf 01.基础架构:一条SQL查询语句是如何执行的?.mp3 01.基础架构:一条SQL查询语句是如 ...

  10. 【前端知识点】promise简书-30分钟带你搞懂promise面试必备

    前言 写作初衷 本书的目的是以目前还在制定中的ECMAScript 6 Promises规范为中心,着重向各位读者介绍JavaScript中对Promise相关技术的支持情况. 通过阅读本书,我们希望 ...

最新文章

  1. iOS原生与html交互 使用第三方WebViewJavascriptBridge
  2. LinuxMint13安装无密码访问git
  3. 如何编译和运行C++程序
  4. python中copy怎么用_python中的拷贝copy模块怎么使用?
  5. sor迭代法matlab实例,Jacobi G-S SOR迭代法在matlab中例子.pdf
  6. 在博客园写了一年博客,收获的不仅仅是写作技能——我能一直保持积极的学习和工作态度...
  7. angr学习笔记(13)(static_binary)
  8. tensorflow随笔-线性拟合以及tensorboard
  9. 怎么使图表居中显示_【Excel技巧】制作柱形图图表完美呈现百分比,提升您的报表颜值...
  10. .Net Core with 微服务 - Consul 注册中心
  11. BOM(Browser Object Model)
  12. 【LeetCode】19. Remove Nth Node From End of List
  13. 【C语言】常用字符(string库函数,ctype库函数),字符数组的输入与处理)
  14. 001. 为input type=text 时设置默认值
  15. 《程序员修炼之道——从小工到专家》 读书笔记
  16. 查看计算机内存条型号,查看本机内存条型号_查看电脑内存条型号
  17. (function ($, undefined){ })(jQuery); 的使用及说明
  18. UMLChina建模竞赛题大全-题目全文+分卷自测(10套100题)
  19. ML:MLOps系列讲解之《设计机器学习驱动的(ML-powered)软件—我们想要解决的业务问题是什么?》解读
  20. VMware workstation虚拟硬盘、类型分析

热门文章

  1. MySQL无法启动,服务没有报告任何错误
  2. PHP-swoole 聊天室
  3. SpringBoot整合支付宝APP支付
  4. 冉宝的每日一题--8月8日--前缀和+拓扑排序复习
  5. CorelDRAW2022增强版CDR2022新版功能
  6. 510房产网是江阴知名的房地产服务平台
  7. wps2016向程序发送命令_老司机帮您向程序发送命令时出现错误 【操作步骤】 的设置办法...
  8. [Unity]Unity3D游戏引擎游戏开发软件相比与其他的优势
  9. 压缩文件已损坏怎么办?恢复压缩文件,解决方法看这里
  10. wangEditor富文本自定义图片宽度