co源码解读

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源码中行数最多的一个函数了? 具体做的事儿呢;

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

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

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

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

{
  a: Promise.resolve('hello'),
  b: Promise.resolve('world')
}
// =>
{
  a:'hello',
  b:'world'
}

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

小记:

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

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏互联网杂技

前端--理解 Promise 的工作原理

Javascript 采用回调函数(callback)来处理异步编程。从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的...

39960
来自专栏性能与架构

使用JS开发桌面应用

Javascript在web开发中已经稳稳的占据了重要位置,现在已经开始渗透到桌面开发了 Electron 便是用来创建桌面应用的框架 使用 JavaScrip...

55960
来自专栏性能与架构

WEB开发将不再重度依赖JS

Mozilla、谷歌、微软、苹果 4大浏览器一致通过了一个标准:WebAssembly WebAssembly 允许使用更多的语言来开发web应用,并且有接近...

35840
来自专栏zhisheng

干货分享:让你分分钟学会 javascript 闭包 一像素

闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它。...

36350
来自专栏互联网杂技

史上最明了的编程语言琅琊榜介绍:JavaScript是剪刀?

小时候经常看局座的节目,得知局座掌握中、英、日、阿拉伯等多门语言 时羡慕不已,当时就许下一个心愿「我一定要成为掌握多门语言的男人」。今天,我的梦想终于实现了,我...

38750
来自专栏性能与架构

Stack Overflow 开发者调查报告

今天看了Stack Overflow 开发者调查统计结果,有几个数据感到意外,没有想到 1. JS已经火到不行 在最受开发者欢迎的语言中,JS继续领先,这倒...

30650
来自专栏性能与架构

ES6 新特性示例

JS的新版本 ES6/ECMAScript2015 在去年出来了,我们现在普遍使用的ES5是在2009年出来的,相隔这么多年,变化比较大,添加了一些很好用的特性...

31860
来自专栏smy

pc浏览器css和js计算浏览器宽度的差异以及和滚动条的关系

如图: css宽度:1250 不包括滚动条宽度 用控制台箭头选取元素显示的左边的宽度:1250  不包含滚动条宽度 缩放浏览器右上角显示的宽度:1267 包含了...

32460
来自专栏互联网杂技

2017值得一瞥的JavaScript相关技术趋势

? 跨年前两天,Dan Abramov在Twitter上提了一个问题: ? JS社区毫不犹豫的抛出了它们对于新技术的预期与期待,本文内容也是总结自Twitt...

35440
来自专栏性能与架构

WEB开发将不再重度依赖JS【二】

前阶段写了一篇文章 "WEB开发将不再重度依赖JS",介绍了 WASM(WebAssembly),因为有了最新消息,所以写了这篇文章来分享 简单回顾一下 WAS...

40840

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励