Promise模式的工作原理

198次阅读
没有评论

共计 3455 个字符,预计需要花费 9 分钟才能阅读完成。

Promise模式的工作原理


为什么需要Promise模式

Promise解释之前,我们提一下华罗庚讲《统筹方法》时提到的烧水喝茶的例子,在烧水的同时做一些其他的泡茶准备工作。这种思想可以让我们合理安排一项任务的工序,从而节约时间。具体如下:

Promise模式的工作原理

我们在这里简化一下,借用它来讲解Promise模式。

假设为了泡茶,我们需要做两项任务, 分别是:烧水(用时15分钟) 和 准备茶杯, 茶叶(用时3分钟)。

泡茶任务的两种执行方式

同步执行

即在开启烧水任务后,等待水沸腾,  发出蜂鸣声后(获取到烧水任务完成的信号),再开启另一项任务,开始准备茶杯和茶叶(用时3分钟),则整个泡茶过程需要18分钟。如图:

Promise模式的工作原理

异步执行

在开启烧水任务后, 并不需要等待烧水任务全部完成,,就可以执行准备茶杯茶叶的任务,完成准备茶杯茶叶任务后,,等待烧水任务执行结束的信号(蜂鸣声),则完成了泡茶的准备工作,整个过程需要15分钟,比同步执行更快。如图:

Promise模式的工作原理

以上便是一个Promise模式在日常生活中的一个运用。Promise模式是一种异步编程模式. 其核心的是, 执行任务A(例如烧水)时, 其执行结果可通过一个promise对象来获取。因而并不需要同步等待任务A结束再去执行任务B。任务B可以与任务A同时执行,它需要任务A执行的结果时, 通过这个promise对象获取即可(例如去听蜂鸣声)。

在烧水喝茶的例子,Promise模式的好处显而易见,泡茶的总时长减少了。在程序中,这意味着程序会运行更快,因为Promise可以避免不必要的等待,  提高对并发的支持。

 Promise模式介绍

Promise模式主要由4部分构成:

  1. Promisor
  2. Executor
  3. Promise
  4. Result

下面一幅图说明这个四个部分的构成关系,:

  1. Executor需要在Promisor的create()方法中去执行。
  2. create()的返回值就是Promise。
  3. Result则是Promise中get()方法的返回值。

看到这里, 如果你还是觉得云里雾里的,没关系,下面我们结合例子详细讲解。如图:

Promise模式的工作原理

Promisor类: 对外暴露一个方法create(),   一旦执行了这个create()方法, 两件事情就发生了:

1、执行器Executor开始异步执行任务。

2、Promisor会创建并返回一个Promise。

这就好比, 一方面开启了烧水的这个异步任务, 另一个方面开始等待水沸腾的蜂鸣声音。如图:

Promise模式的工作原理

Executor: 在Promisor中定义好一个任务, Executor异步执行这个任务。换句话来讲, 就是Promisor决定了,接下来要去异步开启烧水,  然后按下Executor的按钮,它就开启行动啦。

Promise: 是Promisor的create()方法的返回值,这里是立刻返回的,就像买彩票时候拿到的号码。虽然在买彩票的那一刻,不知道结果, 不过你也不需要在彩票站等待, 直接拿着号码就可以回去了。等开奖时间到了,  就可以用这个号码查询自己有没有中奖。 而Promise就好比这个号码,可以立刻返回得到,不会阻塞程序运行.。

方法介绍:

   1、isDone()方法:

烧水的结果, 可能是沸腾了,也就是烧好了。也可能正在加热中。所以Promise中一般会有方法isDone()方法表示任务是在执行中还是已经结束了,放到彩票的例子中就像会告诉你彩票开奖时间是否到啦, 但是不会告诉你结果。

   2、get()方法:

获取任务执行的结果, 就好比, 烧水是加热到沸腾, 发出峰鸣声音啦, 还是把水壶给烧漏掉了, 失败啦。此时, 聪明的你们, 可能要问, 这不是要等上一段时间才能知道吗? 刚刚开始烧水, 怎么能知道结果是沸腾了, 还是水壶漏了呢?  这就引出了get()方法的关键:需要阻塞等待, 只有经过了阻塞等待, 才能知道结果哟。放到彩票的例子中, get()方法就像是一直在电视机前等着看开奖结果, 等着等着,直到中奖结果公布。如图

Promise模式的工作原理

Result: 最简单的一个部分,  其实就是Promise中get()方法的返回值, 放到彩票的例子中, 就是开奖结果。

上面我们详细分析了这四个部分的结构关系,  下面再从时序的角度来再次看待一下这4个部分.如图

Promise模式的工作原理

没有Promise模式时, 泡茶问题的代码如何执行?

下面用java代码来模拟烧水例子的全过程。我们会分别用 非Promise模式 和 Promise模式 来写两套代码进行对比。

非Promise模式泡茶

先设定两个类, 一个是BoilWater表示烧水,在代码中new BoilWater()表示开始烧水,其中status等于true表示烧水完成。另一个是TeaAndCup表示准备茶叶茶杯,同样, 在代码中new TeaAndCup表示开始准备茶叶茶杯,其中status等于true表示准备茶叶茶杯完成。如图:

Promise模式的工作原理

做好了铺垫,下面就可以看非Promise模式时的代码啦,如图:

Promise模式的工作原理

运行结果如下: 如图

Promise模式的工作原理

可以看到,任务一(烧水) 和 任务二(准备茶叶茶杯) 因为一个join()方法的介入,先把任务一(烧水)结束之后,再开始执行任务二。这时两个任务是串行执行的,多线程也失去了意义。

看到这里,好奇的你可能会问,为啥需要执行join()方法呢? 异步执行不就可以了吗, 为了回答这个问题, 我们把join()注释掉, 再来执行以下程序, 看一看结果。没有join()的程序的执行结果,如图

Promise模式的工作原理

可以看到,任务一结束竟然是在准备工作结束之后。这说明任务一(烧水)还没执行结束。主程序就结束了。 烧水还没结束,主程序就任务准备工作结束啦,这显然是不符合要求的。如图

Promise模式的工作原理

 

这真是矛盾啊,如果串行执行呢,结果是正确的,可是没有做到异步。效率不高;如果直接开启异步任务呢, 主程序又提前执行结束了, 如何解决这个问题呢? 那就需要Promise模式了! 这个代码,下回分解!

总结与展望

本篇文章先让大家讲了一个经典的烧水泡茶的例子,说明需要异步多线程执行,效率才更高,。也就是使用Promise模式的原因了。 再结合流程图和时序图, 讲解了Promise模式的原理, 主要是解释了1:Promisor, 2:Executor,  3:Promise,4:Result的作用,我们还特别强调了promise中get()方法是阻塞的。  最后, 把泡茶的例子用java代码实现了一下,  通过观察程序的结果,我们再次验证:Promise模式使得我们的程序兼顾了高效率与正确性。

下篇文章我们会在Promise模式下使用java代码实现泡茶的例子,并和这篇文章结尾中非promise模式的代码做个对比。彻底理解了Promise模式之后,我们会深入一个更复杂的例子当中,去探讨一下,如何解决个人云盘本地文件同步太慢的问题。敬请期待!

正文完
 
yangleduo
版权声明:本站原创文章,由 yangleduo 2023-07-21发表,共计3455字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。