co源码解读
背景:
闲来无事,翻了下co的源码来看,源码短小精悍,算上注释,一共240行左右;
决定写一篇博客来记录下学习的心得。
TJ大神的co:https://github.com/tj/co
作用:
co通过将Generator函数拆成一个Promise将码农从callback hell中拯救了出来;
下边放出一段代码,对比下co与普通回调版本的区别:
/**
* 回调版本
*/ let fs = require('fs') fs.readFile('./package.json', (err, data) => {
if (err) {
return console.log(err)
}
console.log(data.toString())
fs.readFile('./package.json', (err, data) => {
if (err) {
return console.log(err)
}
console.log(data.toString())
})
}) /**
* co版本
*/ let co = require('co')
let fs = require('fs') co(function * () {
let a = yield fs.readFile.bind(null, './package.json')
console.log(a.toString())
let b = yield fs.readFile.bind(null, './package.json')
console.log(b.toString())
}).then(console.log, console.error)
从代码上看,貌似co是一个同步执行的过程呢。当然,也只是看起来像而已。
正题:
先来说一下co整个执行的过程:
- 调用co,传入一个Generator函数,函数会返回一个Promise对象
- 如果传入参数为Generator函数,会执行该函数来进行Generator的初始化
- 手动执行一次next() 这时Generator函数就会停在第一次遇到yield关键字的地方
- 获取到yield后边的值,将其转换为一个Promise函数,然后执行之
- 重复上边两步,直到函数执行完毕
co关于yield后边的值也是有一定的要求的,只能是一个 Function|Promise|Generator | Array | Object;
而 Array和Object中的item也必须是 Function|Promise|Generator。
并且关于function 普通函数并不一定会得到预期的结果,co需要的是 接收一个回调函数 并执行的函数,类似于这样:
function doSomething (callback) {
callback(null, 'hello')
}
co(function * () {
let result = yield doSomething
console.log(result) // => hello
})
总而言之,co执行的肯定是一个Promise,而co会帮你把其他几种类型的值转换为Promise,co绝大部份的代码都是在处理类型的转换;
当然,在讲类型转换的那一块之前,还是将co执行Generator的那几个函数说一下子,也就是调用co返回的Promise中的那三个函数(onFulfilled、onRejected、next);
因next与Generator对象的next方法名相同 这里使用 gen.next 表示 Generator对象的next方法。
onFulfilled:
调用gen.next并将上次执行的结果传入gen.next;
调用next,将gen.next返回的值传入next。
onRejected:
执行流程与 onFulfilled 一致,只不过是将调用的 gen.next 换为了 gen.throw 用来将错误异常抛出。
next:
函数会判断传入参数的done属性,如果为true( 则表示该Generator已经执行完毕),会调用co返回的Promise对象的resolve方法,结束代码执行;
如果done为false 则表示还需要继续执行,这里会将 yield后边的值(参数的value属性)转换为Promise,并调用then方法传入 onFulfilled 和 onRejected两个函数。
co整个的执行流程其实就是这样的-.-
剩余代码所完成的事情就是将各种不同的类型转换为可执行的Promise对象。
thunkToPromise(Function):
函数返回一个Promise对象,在Promise内部执行了传入的function;
并会认为回调的第一个参数为Error(这个貌似是个标准...);
将其余参数打包到一个数组中返回。
arrayToPromise(Array):
Promise有一个方法叫做all,会返回数组中所有Promise执行后的返回值(如果有其中一项被reject掉,所有的都会被reject);
方法会返回 Promise.all() 的执行结果
Promise.all([
Promise.resolve('hello'),
Promise.resolve('world')
]).then(data => {
console.log(data) // => ['hello', 'world']
})
objectToPromise(Object):
函数用来将一个Object对象转换为Promise;
应该是co源码中行数最多的一个函数了
co源码解读的更多相关文章
- SDWebImage源码解读之SDWebImageDownloaderOperation
第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...
- SDWebImage源码解读 之 NSData+ImageContentType
第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...
- SDWebImage源码解读 之 UIImage+GIF
第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...
- SDWebImage源码解读 之 SDWebImageCompat
第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...
- SDWebImage源码解读_之SDWebImageDecoder
第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...
- SDWebImage源码解读之SDWebImageCache(上)
第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...
- SDWebImage源码解读之SDWebImageCache(下)
第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...
- AFNetworking 3.0 源码解读 总结(干货)(下)
承接上一篇AFNetworking 3.0 源码解读 总结(干货)(上) 21.网络服务类型NSURLRequestNetworkServiceType 示例代码: typedef NS_ENUM(N ...
- AFNetworking 3.0 源码解读 总结(干货)(上)
养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...
- AFNetworking 3.0 源码解读(十一)之 UIButton/UIProgressView/UIWebView + AFNetworking
AFNetworking的源码解读马上就结束了,这一篇应该算是倒数第二篇,下一篇会是对AFNetworking中的技术点进行总结. 前言 上一篇我们总结了 UIActivityIndicatorVie ...
随机推荐
- 【一起学OpenFOAM】系列由来
1 为什么要学习OpenFOAM 掐指算起来,接触CFD也差不多有十个年头了,其间一直使用的商用CFD软件,有Fluent.CFX.StarCCM+等,这些商用软件各有其优缺点,都能较好的解决常规的工 ...
- SSD框架训练自己的数据集
SSD demo中详细介绍了如何在VOC数据集上使用SSD进行物体检测的训练和验证.本文介绍如何使用SSD实现对自己数据集的训练和验证过程,内容包括: 1 数据集的标注2 数据集的转换3 使用SSD如 ...
- ASP.NET MVC Model验证(一)
ASP.NET MVC Model验证(一) 前言 前面对于Model绑定部分作了大概的介绍,从这章开始就进入Model验证部分了,这个实际上是一个系列的Model的绑定往往都是伴随着验证的.也会在后 ...
- ABP(现代ASP.NET样板开发框架)系列之14、ABP领域层——领域事件(Domain events)
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之14.ABP领域层——领域事件(Domain events) ABP是“ASP.NET Boilerplate P ...
- Java基础知识(壹)
写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...
- Atitit 软件架构方法的进化与演进cs bs soa roa msa attilax总结
Atitit 软件架构方法的进化与演进cs bs soa roa msa attilax总结 1.1. 软件体系架构是沿着单机到 CS 架构,再到 BS 的三层架构甚至多层架构逐步发展过来的,关于 ...
- 解析大型.NET ERP系统 设计异常处理模块
异常处理模块是大型系统必备的一个组件,精心设计的异常处理模块可提高系统的健壮性.下面从我理解的角度,谈谈异常处理的方方面面.我的设计仅仅限定于Windows Forms,供参考. 1 定义异常类型 . ...
- android笔记:获取View组件宽度以及ViewTreeObserver
View宽高测量方法: 测量方法有三种,如下: 1)(直接在onCreate()执行) int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureS ...
- angular2系列教程(三)components
今天,我们要讲的是angualr2的components. 例子
- 前端开发工具vue.js开发实践总结
最近有很长时间没有更新博客了,换了公司,全部的心思都放在项目上了.通过这次项目的上线,让我感受最深的是前后端分离后,前端页面的模块化管理,以及前端页面的数据邦定.在接触vue.js之前,我之前端要用到 ...