最近在读guzzle/promise的源码,觉得有点绕,所以这里记录一下。

promise介绍

promise是一个异步操作的标准,它规定了应当如何写一系列相关的异步操作,主要目的是规范化异步操作,避免大量的异步操作导致的回调地域。

Guzzle中的promise

promise是如何规范异步操作的

  • 异步操作的状态只有三种:pending-等待,fulfilled-成功,rejected-失败
  • 异步状态的变化只有两种:pending->fullfilled,pending->rejected
  • promise是可以传递的,也就是说promise A的结果可以是另一个promise B,那么A的成功与否,就要取决于B,B成功了,A就成功了,B失败了,A就失败了
  • 对结果成功与否的操作封装在onFulfilled和onRejected两个函数中
  • 可以手动的调用resolve达成promise,也可以手动调用reject拒绝promise
  • 如果需要同步的等待异步操作完成,可以调用wait方法,但需要在wait方法中达成promise或者拒绝promise
  • 也可以直接cancel某个promise并做相关操作(比reject多的就是可以附加某些相关操作,比如关闭socket链接、数据库链接等)

guzzle中是如何实现异步的

理解了promise的概念,最关键的一个问题应该是php中如何实现异步操作。
我们都知道php是进程级别的,当然也可以使用pthread来引入线程,但引入的线程也是有缺陷的(对资源类型的操作会有风险),且连作者都不推荐在cgi模式下运行。那么在php中如何实现异步操作呢?
guzzle中使用的是队列+register_shutdown_function的方法。
简单的讲,就是将异步操作的具体操作集中到一个队列中,然后注册到register_shutdown_function,在脚本执行完毕时依顺序执行队列中的操作。感觉很有trick…具体代码在TaskQueue中:

if ($withShutdown) {register_shutdown_function(function () {if ($this->enableShutdown) {// Only run the tasks if an E_ERROR didn't occur.$err = error_get_last();if (!$err || ($err['type'] ^ E_ERROR)) {$this->run();}}});
}

如何规定一个promise

在guzzle的promise中,一个promise包含6个属性:

  • state:当前promise的状态
  • result:promise的结果,包括成功的结果和拒绝的结果,可以是另一个promise
  • watiFn:调用wait时执行的function,在构造对象时传入
  • cancelFn:调用cancel时执行的function,在构造对象时传入
  • waitList:当前promise所依赖的promise
  • handler:当前promise保存的操作

类中的方法就很多了,这里不一一介绍,还是介绍几个关键的function。

construct

在构造方法中,需要传入waitFn和cancelFn,当然你也可以不传入。这个方法没什么好说的。

then

这是比较关键的一个方法,它揭示了如何实现链式操作和promise是如何传递的。

// 如果状态是pending,说明仍然没有结果,那么将继续注册onFulfilled和onRejected
if ($this->state === self::PENDING) {// 每次都是创建一个新的promise$p = new Promise(null, [$this, 'cancel']);// 保存每次注册的方法$this->handlers[] = [$p, $onFulfilled, $onRejected];$p->waitList = $this->waitList;// 保存新创建的promise$p->waitList[] = $this;return $p;
}// 如果已经是成功状态,直接执行所有成功操作
if ($this->state === self::FULFILLED) {$promise = Create::promiseFor($this->result);return $onFulfilled ? $promise->then($onFulfilled) : $promise;
}// 如果已经是失败状态,直接执行所有失败操作
$rejection = Create::rejectionFor($this->result);
return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
resolve/reject/settle

将resolve和reject都封装成settle的调用,首先通过下列代码控制了状态的变化规则:

if ($this->state !== self::PENDING) {// Ignore calls with the same resolution.if ($state === $this->state && $value === $this->result) {return;}throw $this->state === $state? new \LogicException("The promise is already {$state}."): new \LogicException("Cannot change a {$this->state} promise to {$state}");
}

后续再根据$value(settle时传入的参数,也就是调用resolve和reject时传入的参数)的类型决定下一步操作:

// 如果value不是promise,则根据state注册操作到queue中
if (!is_object($value) || !method_exists($value, 'then')) {$id = $state === self::FULFILLED ? 1 : 2;Utils::queue()->add(...);
} elseif ($value instanceof Promise && Is::pending($value)) {// 如果是promise且还在pending,则合并操作$value->handlers = array_merge($value->handlers, $handlers);
} else {// 如果是promise且不再pending,则调用$value的then方法,先解决$value$value->then(...,...);
}

对promise这块的理解,我还不是很透彻,先记录到这,后面如果有更新,我在补充上。

Guzzle/promises源码解读相关推荐

  1. Bert系列(二)——源码解读之模型主体

    本篇文章主要是解读模型主体代码modeling.py.在阅读这篇文章之前希望读者们对bert的相关理论有一定的了解,尤其是transformer的结构原理,网上的资料很多,本文内容对原理部分就不做过多 ...

  2. Bert系列(三)——源码解读之Pre-train

    https://www.jianshu.com/p/22e462f01d8c pre-train是迁移学习的基础,虽然Google已经发布了各种预训练好的模型,而且因为资源消耗巨大,自己再预训练也不现 ...

  3. linux下free源码,linux命令free源码解读:Procps free.c

    linux命令free源码解读 linux命令free源码解读:Procps free.c 作者:isayme 发布时间:September 26, 2011 分类:Linux 我们讨论的是linux ...

  4. nodeJS之eventproxy源码解读

    1.源码缩影 !(function (name, definition) { var hasDefine = typeof define === 'function', //检查上下文环境是否为AMD ...

  5. PyTorch 源码解读之即时编译篇

    点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 作者丨OpenMMLab 来源丨https://zhuanlan.zhihu.com/ ...

  6. Alamofire源码解读系列(九)之响应封装(Response)

    本篇主要带来Alamofire中Response的解读 前言 在每篇文章的前言部分,我都会把我认为的本篇最重要的内容提前讲一下.我更想同大家分享这些顶级框架在设计和编码层次究竟有哪些过人的地方?当然, ...

  7. Feflow 源码解读

    Feflow 源码解读 Feflow(Front-end flow)是腾讯IVWEB团队的前端工程化解决方案,致力于改善多类型项目的开发流程中的规范和非业务相关的问题,可以让开发者将绝大部分精力集中在 ...

  8. spring-session源码解读 sesion

    2019独角兽企业重金招聘Python工程师标准>>> spring-session源码解读 sesion 博客分类: java spring 摘要: session通用策略 Ses ...

  9. 前端日报-20160527-underscore 源码解读

    underscore 源码解读 API文档浏览器 JavaScript 中加号操作符细节 抛弃 jQuery,拥抱原生 JS 从 0 开始学习 GitHub 系列之「加入 GitHub」 js实现克隆 ...

最新文章

  1. 原来博客园的日历是这样用的!
  2. dz如何安装mysql_windows下安装Mysql(图文详解)
  3. php中var_dump是什么意思,php中的var_dump()方法的詳細說明
  4. 汇编语言(十九)之删除数组中的元素
  5. 用 Python 下载抖音无水印视频
  6. 【转】什么是磁珠(Ferrite Bead 即 FB)
  7. 让两个Div并排显示
  8. Lambda演算与科里化(Currying)
  9. 《推荐系统实践》算法纯享(附代码链接)(三)—— 冷启动篇
  10. 【PTA-python】第4章-15 换硬币 (20 分)
  11. xcb_query_extension_reply_t的解释
  12. 职场菜鸟捕食指北【初入职场篇】
  13. Unity UGUI-Canvas
  14. 哪些业务需要使用CDN加速服务?
  15. 点云IO篇之stl文件读写
  16. 2023最新苹果APP上架App Store流程(超详细)
  17. 看了数据分析师的摆摊神操作,网友:这才叫专业
  18. 这或许是全网最全 Python dataframe 数据合并方法汇总
  19. linux系统下怎么安装.deb文件?
  20. sqlserver不同版本之间数据库的还原方法

热门文章

  1. 阶乘分解——质因数分解
  2. maven 开源中国配置~
  3. 计算机报名无法支付mac,支付宝在Mac电脑中无法登录怎么办?
  4. 为四则运算设计一个类python_python的四则运算练习
  5. Python爬虫实例:自制翻译机(简单)
  6. C# 多线程Thread.IsBackground=True的作用
  7. text-align的用法
  8. 分布式数据库理论知识之CAP理论、ACID原则及分布式事务一致性算法
  9. 软件测试笔记:黑盒测试——边界测试
  10. HDU——1863 畅通工程(最小生成树问题)