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 相关文章推荐
最新优化收藏到网摘代码(digg,diigo)
Feb 07 Javascript
Ajax,UTF-8还是GB2312 eval 还是execScript
Nov 13 Javascript
S2SH整合JQuery+Ajax实现登录验证功能实现代码
Jan 30 Javascript
Jquery实现视频播放页面的关灯开灯效果
May 27 Javascript
jquery实现预览提交的表单代码分享
May 21 Javascript
javascript查询字符串参数的方法
Jan 28 Javascript
AngularJS的内置过滤器详解
May 14 Javascript
JS获取复选框的值,并传递到后台的实现方法
May 30 Javascript
Js利用console计算代码运行时间的方法示例
Sep 24 Javascript
纯JS实现出生日期[年月日]下拉菜单效果
Jun 01 Javascript
微信小程序自定义轮播图
Nov 04 Javascript
微信小程序-form表单提交代码实例
Apr 29 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中VC6 X86和VC9 X86的区别及 Non Thread Safe的意思
2013/06/28 PHP
PHP实现图片不变型裁剪及图片按比例裁剪的方法
2016/01/14 PHP
PHP array_key_exists检查键名或索引是否存在于数组中的实现方法
2016/06/13 PHP
浅谈Yii乐观锁的使用及原理
2017/07/25 PHP
PHP在同一域名下两个不同的项目做独立登录机制详解
2017/09/22 PHP
php操作mongodb封装类与用法实例
2018/09/01 PHP
PHP中常用的三种设计模式详解【单例模式、工厂模式、观察者模式】
2019/06/14 PHP
控制打印时页眉角的代码
2007/02/08 Javascript
js控制当再次点击按钮时的间隔时间
2014/06/03 Javascript
jQuery EasyUI API 中文帮助文档和扩展实例
2016/08/01 Javascript
几种二级联动案例(jQuery\Array\Ajax php)
2016/08/13 Javascript
Javascript使用SWFUpload进行多文件上传
2016/11/16 Javascript
jQuery动态生成表格及右键菜单功能示例
2017/01/13 Javascript
Angular2学习教程之ng中变更检测问题详解
2017/05/28 Javascript
在vue.js中使用JSZip实现在前端解压文件的方法
2018/09/05 Javascript
浅谈JS和jQuery的区别
2019/03/27 jQuery
[10:05]DOTA2-DPC中国联赛 正赛 iG vs PSG.LGD 选手采访
2021/03/11 DOTA
python连接远程ftp服务器并列出目录下文件的方法
2015/04/01 Python
Python中的descriptor描述器简明使用指南
2016/06/02 Python
使用Django简单编写一个XSS平台的方法步骤
2019/03/25 Python
Python实现队列的方法示例小结【数组,链表】
2020/02/22 Python
python实现字符串和数字拼接
2020/03/02 Python
Dune London官网:英国著名奢华鞋履品牌
2017/11/30 全球购物
英国老牌潮鞋店:Offspring
2019/08/19 全球购物
介绍一下Java中的static关键字
2012/05/12 面试题
教育科学研究生自荐信
2013/10/09 职场文书
家佳咖啡店创业计划书
2013/12/27 职场文书
《画风》教学反思
2014/04/16 职场文书
财务工作检讨书
2014/10/29 职场文书
农村党员干部承诺书
2015/05/04 职场文书
入团介绍人意见范文
2015/06/04 职场文书
紫日观后感
2015/06/05 职场文书
护士业务学习心得体会
2016/01/25 职场文书
创业计划书之蛋糕店
2019/08/29 职场文书
何时使用Map来代替普通的JS对象
2021/04/29 Javascript
Win11右下角图标点了没反应怎么办?Win11点击右下角图标无反应解决方法汇总
2022/07/07 数码科技