Koa源码分析(一) -- generator
Abstract
本系列是关于Koa框架的文章,目前关注版本是Koa v1。主要分为以下几个方面:
1. Koa源码分析(一) -- generator
2. Koa源码分析(二) -- co的实现
3. Koa源码分析(三) -- middleware机制的实现
Genetator函数
Generator函数是ES6提供的一种异步编程解决方案,其语法行为完全不同于传统函数。
详细解析可见阮一峰老师的《ECMAScript 6 入门 --- Generator》
语法
两大特征
function关键字与函数名之间的*- 函数体内部使用
yield语句
我们定义一个generatorFunction示例:
function* firstGenerator() {
var one = yield 'one';
console.log(one);
var two = yield 'two';
concole.log(two);
var third = yield 'third';
console.log(third);
return 'over'
}
带有 * 的函数声明就代表 firstGenerator 函数是一个generator函数,函数里面的 yield 关键字可以理解为在当前位置设置断点,这一点如有疑问,可以看后续。
语法行为
那generator函数的语法行为究竟与传统函数不同在哪里呢?下边我们来梳理下generator函数的运行步骤。
var it = firstGenerator();
console.log(it.next(1)); // {value: "one", done: false}
console.log(it.next(2)); // {value: "two", done: false}
console.log(it.next(3)); // {value: "third", done: false}
console.log(it.next(4)); // {value: "over", done: true}
首先通过执行 firstGenerator 函数,我们可以得到一个generator对象 it,它是一个迭代器对象。此时, firstGenerator 函数并未执行,只是返回了迭代器对象 it ,我们可以通过 it 对象中 next 方法触发 firstGenerator 函数开始执行,此时我们调用 it.next(1),注意 next 注入的参数 1 并没有任何效果。当 firstGenerator 函数执行到 yield 语句时,被打了断点,停留在此处,并将 yield 后的变量传递给 it.next(1) 结果对象中的 value 字段,另外其中的 done 字段表示 firstGenerator 函数尚未完全执行完,还停留在断点。以此同时,将执行权交换给 it.next(1)。
执行第二次 it.next(2),执行权再次交给 firstGenerator 函数,并将 next 带入的参数传递给函数中的变量 one,此时输出 2。当运行到 yield 'two' 语句时,再次将执行权返回给 it.next(2) 并传值。
第三次执行 it.next(3)的过程与第二次完全一样。
最后一次执行 it.next(4) 时,在此之前, firstGenerator 函数断点在 var third = yield 'third',当 it.next(4) 将执行权交给 firstGenerator 函数时,将 4 传递给变量 third,此刻输出 4。当执行到 return 语句时,整个函数已经执行完了,并将 'over'传递给 it.next(4) 返回结果中的 value 字段,且 done 字段为 true。若没有 return 语句,则 value 字段返回 null。
这样下来,整个 firstGenerator 整个函数执行完毕。我们可以将Generator函数比喻成懒惰的癞蛤蟆,每次都需要使用it.next()方法戳一下,才会有对应的行动。如果大家了解python中协程的概念,应该很好理解Generator函数的语法行为。
进阶语法
在Generator函数中 yield 的语法,其后边的值也可以是函数、对象等等。 yield 后边可以是另一个Generator对象。
function* subGen() {
console.log('step in sub generator');
var b = yield 'sub 1';
console.log(b);
console.log('step out sub generator');
}
var subGenerator = new subGen();
function* mainGen() {
var a = yield 'main 1';
console.log(a);
var b = yield *subGenerator;
console.log(b);
var c = yield 'main 2';
console.log(c);
return 'over';
}
var it = mainGen();
console.log(it.next(1));
// {value: 'main 1', done: false}
console.log(it.next(2));
// 2
// step in sub generator
// {value: 'sub 1', done: false}
console.log(it.next(3));
// 3
// step out sub generator
// null
// {value: 'main 2', done: false}
console.log(it.next(4));
// 4
// {value: 'over', done: true}
yield 后面跟着 *subGenerator 对象,这等同于断点就进入 subGenerator 的 subGen里面,等待 subGen 全部执行完后再回来继续执行,类似于递归。
直白点说,就是将 subGen 内嵌到 mainGen中。
在subGen函数中的return语句并不会起到断点的作用
结束语
Generator函数作为ES6的新特性,通过它可以很好的解决JavaScript中的恶魔回调问题。Koa框架使用这特性很好组织了异步代码的结构。
Koa源码分析(一) -- generator的更多相关文章
- Koa源码分析(三) -- middleware机制的实现
Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...
- Koa源码分析(二) -- co的实现
Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...
- Node.js躬行记(19)——KOA源码分析(上)
本次分析的KOA版本是2.13.1,它非常轻量,诸如路由.模板等功能默认都不提供,需要自己引入相关的中间件. 源码的目录结构比较简单,主要分为3部分,__tests__,lib和docs,从名称中就可 ...
- koa源码分析
最近项目要使用koa,所以提前学习一下,顺便看了koa框架的源码. 注:源码是koa2.x koa的源码很简洁,关键代码只有4个文件,当然还包括一些依赖npm包 const Koa = require ...
- Node.js躬行记(20)——KOA源码分析(下)
在上一篇中,主要分析了package.json和application.js文件,本文会分析剩下的几个文件. 一.context.js 在context.js中,会处理错误,cookie,JSON格式 ...
- koa2中间件koa和koa-compose源码分析原理(一)
koa是基于nodejs平台的下一代web开发框架,它是使用generator和promise,koa的中间件是一系列generator函数的对象.当对象被请求过来的时候,会依次经过各个中间件进行处理 ...
- co源码分析及其实践
本文始发于我的个人博客,如需转载请注明出处. 为了更好的阅读体验,可以直接进去我的个人博客看. 前言 知识储备 阅读本文需要对Generator和Promise有一个基本的了解. 这里我简单地介绍一下 ...
- koa-convert源码分析
koa-convert最主要的作用是:将koa1包中使用的Generator函数转换成Koa2中的async函数.更准确的说是将Generator函数转换成使用co包装成的Promise对象.然后执行 ...
- 新一代web框架Koa源码学习
此文已由作者张佃鹏授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Koa 就是一种简单好用的 Web 框架.它的特点是优雅.简洁.表达力强.自由度高.本身代码只有1000多行 ...
随机推荐
- Vim 简明教程【转载】
简明 Vim 练级攻略 第一级 – 存活 安装 vim 启动 vim 什么也别干!请先阅读 当你安装好一个编辑器后,你一定会想在其中输入点什么东西,然后看看这个编辑器是什么样子.但vim不是这样的,请 ...
- celery (二) task
Task task 具有如下特点: task 可以在任何可调用的地方创建.它有双重角色: 定义了当task被调用时,会发送一个消息. 定义了当worker收到消息时会运行消息对应的函数 每个task都 ...
- Apple watch ,小米微信通知
Applewatch怎么显示微信通知?iWatch显示微信消息通知设置方法.大家都知道Applewatch上收到微信消息,iWatch是不会显示通知的,需要用户自行设置才行.下面小编来教大家如何设置A ...
- JVM、redis缓存适用场景
1. 数据状态相对稳定:(针对数据本身)数据修改较少. 2. 输出的数据是相对幂等:(针对业务)多次查询期间,数据不变动.如果查询频率过高,缓存可能没有及时更新. 了解一下redis.ehcache. ...
- editplus注册码
EditPlus5.0注册码 注册名 Vovan 注册码 3AG46-JJ48E-CEACC-8E6EW-ECUAW EditPlus3.x注册码 EditPlus注册码生成器链接 http://ww ...
- Day05 -寻找自己:Ruby的self物件与singleton method
前情提要:在第四天里,我们用参赛者的例子解说实体方法与类别方法.类别中的实体物件,想要玩弄方法时,可以有三种取用方式:(跟斯斯有三种一样) 该类别所定义的实体方法. 模块中可取得的实体方法.(关于模块 ...
- k8s 代码生成
https://blog.openshift.com/kubernetes-deep-dive-code-generation-customresources/ # 代码生成的工作目录,也就是我们的项 ...
- unity中给图片换颜色
slot边框.color = new Color32 (93,165,255,255);
- Selenium Grid和IE /Firefox各种填坑
使用selenium grid的步骤 1.确保hub和node都安装并且配置好了java jdk. 2.在hub上运行以下命令. java -jar C:\Software\selenium\sele ...
- lambda练习题
3.用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb name=['alex','wupeiqi','yuanhao','nezha'] # def func(item): # ...