co源码解读

简介: 背景:     闲来无事,翻了下co的源码来看,源码短小精悍,算上注释,一共240行左右;     决定写一篇博客来记录下学习的心得。     TJ大神的co:https://github.com/tj/co   作用:     co通过将Generator函数拆成一个Promise将码...

背景:

    闲来无事,翻了下co的源码来看,源码短小精悍,算上注释,一共240行左右;

    决定写一篇博客来记录下学习的心得。

    TJ大神的co:https://github.com/tj/co

 

作用:

    co通过将Generator函数拆成一个Promise将码农从callback hell中拯救了出来;

 

    下边放出一段代码,对比下co与普通回调版本的区别:

 1 /**
 2  *  回调版本
 3  */
 4 
 5 let fs = require('fs')
 6 
 7 fs.readFile('./package.json', (err, data) => {
 8   if (err) {
 9     return console.log(err)
10   }
11   console.log(data.toString())
12   fs.readFile('./package.json', (err, data) => {
13     if (err) {
14       return console.log(err)
15     }
16     console.log(data.toString())
17   })
18 })
19 
20 /**
21  *  co版本
22  */
23 
24 let co = require('co')
25 let fs = require('fs')
26 
27 co(function * () {
28   let a = yield fs.readFile.bind(null, './package.json')
29   console.log(a.toString())
30   let b = yield fs.readFile.bind(null, './package.json')
31   console.log(b.toString())
32 }).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需要的是 接收一个回调函数 并执行的函数,类似于这样:

1 function doSomething (callback) {
2   callback(null, 'hello')
3 }
4 co(function * () {
5   let result = yield doSomething
6   console.log(result)  // => hello
7 })

 

    总而言之,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() 的执行结果

1 Promise.all([
2   Promise.resolve('hello'),
3   Promise.resolve('world')
4 ]).then(data => {
5   console.log(data)  // => ['hello', 'world']
6 })

 

 

objectToPromise(Object):

    函数用来将一个Object对象转换为Promise;

    应该是co源码中行数最多的一个函数了  具体做的事儿呢;

    就是将一个Object的每一个key都转换为Promise,并塞到一个数组中;

    执行Promise.all()将上边的数组塞进去;

    当某一个key所对应的Promise函数执行完毕后,会将执行的结果塞回对应的key中;

    全部执行完毕后,就会返回该Object。

 1 {
 2   a: Promise.resolve('hello'),
 3   b: Promise.resolve('world')
 4 }
 5 
 6 // =>
 7 
 8 {
 9   a: 'hello',
10   b: 'world'
11 }

 

 

其余的几个函数就是判断类型了, isPromise、isGenerator、isGeneratorFunction、isObject。

 

小记:

因我司在用koa来搭建web项目,所以会接触到这些东西,就想写点博客记录一下;

本人文笔简直负分,望各位海涵,如有什么不懂的,欢迎邮件骚扰。

jiashunming@outlook.com 

文章相关代码会在GitHub更新:

https://github.com/Jiasm/blog-resource/tree/master/co 

目录
相关文章
|
4天前
|
云安全 人工智能 自然语言处理
|
9天前
|
人工智能 Java API
Java 正式进入 Agentic AI 时代:Spring AI Alibaba 1.1 发布背后的技术演进
Spring AI Alibaba 1.1 正式发布,提供极简方式构建企业级AI智能体。基于ReactAgent核心,支持多智能体协作、上下文工程与生产级管控,助力开发者快速打造可靠、可扩展的智能应用。
839 24
|
3天前
|
机器学习/深度学习 人工智能 自然语言处理
Z-Image:冲击体验上限的下一代图像生成模型
通义实验室推出全新文生图模型Z-Image,以6B参数实现“快、稳、轻、准”突破。Turbo版本仅需8步亚秒级生成,支持16GB显存设备,中英双语理解与文字渲染尤为出色,真实感和美学表现媲美国际顶尖模型,被誉为“最值得关注的开源生图模型之一”。
409 3
|
12天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
814 59
Meta SAM3开源:让图像分割,听懂你的话
|
1天前
|
弹性计算 网络协议 Linux
阿里云ECS云服务器详细新手购买流程步骤(图文详解)
新手怎么购买阿里云服务器ECS?今天出一期阿里云服务器ECS自定义购买流程:图文全解析,阿里云服务器ECS购买流程图解,自定义购买ECS的设置选项是最复杂的,以自定义购买云服务器ECS为例,包括付费类型、地域、网络及可用区、实例、镜像、系统盘、数据盘、公网IP、安全组及登录凭证详细设置教程:
169 114
|
5天前
|
机器学习/深度学习 人工智能 数据可视化
1秒生图!6B参数如何“以小博大”生成超真实图像?
Z-Image是6B参数开源图像生成模型,仅需16GB显存即可生成媲美百亿级模型的超真实图像,支持中英双语文本渲染与智能编辑,登顶Hugging Face趋势榜,首日下载破50万。
355 19
|
2天前
|
人工智能 安全 小程序
阿里云无影云电脑是什么?最新收费价格个人版、企业版和商业版无影云电脑收费价格
阿里云无影云电脑是运行在云端的虚拟电脑,分企业版和个人版。企业版适用于办公、设计等场景,4核8G配置低至199元/年;个人版适合游戏、娱乐,黄金款14元/月起。支持多端接入,灵活按需使用。
246 164