JS co 函数库的含义和用法实例总结


Posted in Javascript onApril 08, 2020

本文实例讲述了JS co 函数库的含义和用法。分享给大家供大家参考,具体如下:

继续学习阮一峰老师异步编程四部曲之三:co

co在很早之前就听超哥讲过,说在node编程中大量用到,源码很简单,但是想法很强大。

让我有空抓紧了解下,前一段时间弄离职的事情,跑来跑去累的够呛。

现在终于一切回归正常了,还在拼命的适应新公司的节奏。只能趁周末继续学习了。

好了,不瞎扯了,回归主题,前两篇文章我们分别学习了 Generator 函数和 Thunk 方式的自动执行。

今天我们接着上次的思路学习使用 co 工具实现 Generator 函数的自动执行。

再次拿出上一节的示例:

var fs = require('fs');
var thunkify = require('thunkify');
var readFile = thunkify(fs.readFile);
 
var gen = function* (){
 var r1 = yield readFile('/etc/fstab');
 console.log(r1.toString());
 var r2 = yield readFile('/etc/shells');
 console.log(r2.toString());
};

这段代码用于读取两个文件,怎么使用 co 工具来实现自动执行呢?

很简单:

var co = require('co');
co(gen);

上面代码中,只要把 Generator 函数传入 co 函数,就会自动执行。

co 函数返回一个 Promise 对象,因此可以用 then 方法添加回调函数,当 Generator 执行结束就会触发回调:

co(gen).then(function (){
 //success
});

这么看起来的话好像和我们之前的 Thunk 方式差不多啊,只是把 run 函数名改成了 co

唯一的区别是多了一层 Promise 包装,那么 co 和 Thunk 到底有什么区别呢?

正如我们的猜测一样,co 其实是将之前的两种自动执行方式(Thunk 和 Promise)结合到了一起,包装成一个库。

使用它的前提和比Thunk多了一种 Promise 的情况,也就是yield返回值必须是 Thunk 函数和 Promise 对象之一

实现原理:

之前我们在研究 Thunk 函数时的第一步是使用 thunkify 将 readFile 包装成 Thunk 函数:

今天我们研究 Promise 就需要把 readFile 包装成 Promise 对象,看代码:

var fs = require('fs');
 
var readFile = function (fileName){
 return new Promise(function (resolve, reject){
  fs.readFile(fileName, function(error, data){
   if (error) reject(error);
   resolve(data);
  });
 });
};
 
var gen = function* (){
 var f1 = yield readFile('/etc/fstab');
 var f2 = yield readFile('/etc/shells');
 console.log(f1.toString());
 console.log(f2.toString());
};

接下来是我特别喜欢老师做的一件事,先用最原始的方式,手动执行一遍代码。

在我们日常开发的过程中,也可以参考这种方式。当逻辑复杂时,不妨先用最直白的方式把它实现,

然后再去发现里面的规则,去优化重构。又开始扯了,看一下手动执行的代码:

var g = gen();
 
g.next().value.then(function(data){
 g.next(data).value.then(function(data){
  g.next(data);
 });
});

手动执行其实就是用 then 方法,层层添加回调函数。理解了这一点,就可以写出一个自动执行器:

function run(gen){
 var g = gen();  //开始执行
 
 function next(data){
  var result = g.next(data);
  if (result.done) return result.value;
  result.value.then(function(data){
   next(data);
  });
 }
 next();
}
run(gen);

和Thunk函数的区别是,Thunk 函数在执行成功后把 next 传给 thunkify ,让 thunkify 来帮忙执行 next

这里的做法是吧 next 交给 Promise,promise 控制请求成功时执行 next。区别只有这么一点。

分析了原理之后,我们来分析下co的源码:

co 函数接受一个 Generator 参数,返回一个 Promise 对象

function co(gen) {
 var ctx = this;
 
 return new Promise(function(resolve, reject) {
 });
}

在返回的 Promise 对象里面,先检查参数 gen 是否为 Generator 函数。如果是,就执行该函数,得到一个内部指针对象;

如果不是就返回,并将 Promise 对象的状态改为 resolved 。

function co(gen) {
 var ctx = this;
 
 return new Promise(function(resolve, reject) {
  if (typeof gen === 'function') gen = gen.call(ctx);
  if (!gen || typeof gen.next !== 'function') return resolve(gen);
 });
}

接着,co 对 next 方法进行包装,使异常能够暴露出来:

function co(gen) {
 var ctx = this;
 
 return new Promise(function(resolve, reject) {
  if (typeof gen === 'function') gen = gen.call(ctx);
  if (!gen || typeof gen.next !== 'function') return resolve(gen);
 
  onFulfilled();
  function onFulfilled(res) {
   var ret;
   try {
    ret = gen.next(res);
   } catch (e) {
    return reject(e);
   }
   next(ret);
  }  
 });
}

最后就是next方法了:

function next(ret) {
 if (ret.done) return resolve(ret.value);
 var value = toPromise.call(ctx, ret.value);
 if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
 return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
    + 'but the following object was passed: "' + String(ret.value) + '"'));
  }
});

next方法最主要的一行:

if (value && isPromise(value)) return value.then(onFulfilled, onRejected);

co的使用条件,每一次yield返回必须是Promise对象,当promist处理成功时再次执行onFulfilled

以此来达到自动执行的效果。

co 还支持并发的异步操作,yield 返回一个数组或者是支持遍历的对象即可:

// 数组的写法
co(function* () {
 var res = yield [
  Promise.resolve(1),
  Promise.resolve(2)
 ];
 console.log(res); 
}).catch(onerror);
 
// 对象的写法
co(function* () {
 var res = yield {
  1: Promise.resolve(1),
  2: Promise.resolve(2),
 };
 console.log(res); 
}).catch(onerror);

至此,co 的自动执行原理我们已经学习完成了,

其实本质上不是很难,只是涉及到的模块较多,思路比较灵活

对我的小容量大脑来说,现在的认识还只到90%

所以这篇文章里面自己的思想比较少,更多的还是在复述老师的思路。

最后贴上原文的地址:co 函数库的含义和用法

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容可查看本站专题:《JavaScript常用函数技巧汇总》、《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
passwordStrength 基于jquery的密码强度检测代码使用介绍
Oct 08 Javascript
Javascript 异步加载详解(浏览器在javascript的加载方式)
May 20 Javascript
javascript验证上传文件的类型限制必须为某些格式
Nov 14 Javascript
跟我学习javascript的基本类型和引用类型
Nov 16 Javascript
js实现年月日表单三级联动
Apr 17 Javascript
vue插件vue-resource的使用笔记(小结)
Aug 04 Javascript
微信小程序实现下载进度条的方法
Dec 08 Javascript
详解微信小程序实现WebSocket心跳重连
Jul 31 Javascript
jQuery选择器之层次选择器用法实例分析
Feb 19 jQuery
vue服务端渲染操作简单入门实例分析
Aug 28 Javascript
JavaScript面向对象核心知识与概念归纳整理
May 09 Javascript
node.js如何根据URL返回指定的图片详解
Oct 21 Javascript
JS Thunk 函数的含义和用法实例总结
Apr 08 #Javascript
JS Generator 函数的含义与用法实例总结
Apr 08 #Javascript
Vue列表循环从指定下标开始的多种解决方案
Apr 08 #Javascript
《javascript设计模式》学习笔记七:Javascript面向对象程序设计组合模式详解
Apr 08 #Javascript
vue开发移动端底部导航条功能
Apr 08 #Javascript
《javascript设计模式》学习笔记五:Javascript面向对象程序设计工厂模式实例分析
Apr 08 #Javascript
vue实现表单未编辑或未保存离开弹窗提示功能
Apr 08 #Javascript
You might like
浅析PHP递归函数返回值使用方法
2013/02/18 PHP
PHP生成指定随机字符串的简单实现方法
2015/04/01 PHP
设定php简写功能的方法
2019/11/28 PHP
PHP+fiddler抓包采集微信文章阅读数点赞数的思路详解
2019/12/20 PHP
JavaScript中使用构造器创建对象无需new的情况说明
2012/03/01 Javascript
js优化针对IE6.0起作用(详细整理)
2012/12/25 Javascript
浏览器页面区域大小的js获取方法
2013/09/21 Javascript
js实现汉字排序的方法
2015/07/23 Javascript
AngularJS教程之简单应用程序示例
2016/08/16 Javascript
vue-dialog的弹出层组件
2020/05/25 Javascript
vue 实现 tomato timer(蕃茄钟)实例讲解
2017/07/24 Javascript
Js中使用正则表达式验证输入是否有特殊字符
2018/09/07 Javascript
javascript中数组的常用算法深入分析
2019/03/12 Javascript
vue路由中前进后退的一些事儿
2019/05/18 Javascript
你不知道的 TypeScript 高级类型(小结)
2020/08/28 Javascript
[53:52]OG vs EG 2018国际邀请赛淘汰赛BO3 第二场 8.23
2018/08/24 DOTA
python中查找excel某一列的重复数据 剔除之后打印
2013/02/10 Python
linux系统使用python监测系统负载脚本分享
2014/01/15 Python
python实现调用其他python脚本的方法
2014/10/05 Python
Python闭包实现计数器的方法
2015/05/05 Python
Python编程之基于概率论的分类方法:朴素贝叶斯
2017/11/11 Python
浅谈机器学习需要的了解的十大算法
2017/12/15 Python
Python程序运行原理图文解析
2018/02/10 Python
深入理解python中sort()与sorted()的区别
2018/08/29 Python
Pandas过滤dataframe中包含特定字符串的数据方法
2018/11/07 Python
matplotlib jupyter notebook 图像可视化 plt show操作
2020/04/24 Python
用CSS禁用输入法(CSS3 UI规范)实例解析
2012/12/04 HTML / CSS
CSS3中的@keyframes关键帧动画的选择器绑定
2016/06/13 HTML / CSS
Homestay中文官网:全球寄宿家庭
2018/10/18 全球购物
预备党员承诺书
2014/03/25 职场文书
《风筝》教学反思
2014/04/10 职场文书
教师暑期培训感言
2014/08/15 职场文书
面试通知单大全
2015/04/20 职场文书
教师见习总结范文
2015/06/23 职场文书
2016年师德先进个人事迹材料
2016/02/29 职场文书
Node.js实现爬取网站图片的示例代码
2022/04/04 NodeJs