原文链接 http://www.cnblogs.com/ytu2010dt/p/6043947.html

co4.x已经抛弃了原来thunk转而结合promise实现。

一:promise

promsie是es6原声支持的把一步嵌套转换为线型调用的一种方式,angular的$q和node的q包都是基于promise A+规范封装的 。原生使用方法如下

  1. //首先对异步操作封装
    function readFile(path) {
  2. return new Promise(function(resolve, reject) {
  3. fs.readFile(path, 'utf8', function(err, data) {
  4. if (!err) {
  5. resolve(data);
  6. } else {
  7. reject(err);
  8. }
  9. })
  10. });
  11. }
  1. // 调用如下(没次调用完返回一个新的promise,在最后的catch里处理错误)
  2.  
  3. readFile('01.txt')
  1. .then(function(data) {
  2. if (data) {
  3. console.log(data)
  4. return readFile('02.txt')
  5. }
  6. })
  7. .then(function(data) {
  8. if (data) {
  9. console.log(data)
  10. return readFile('03.txt')
  11. }
  12. })
  13. .catch(function(err) {
  14. console.log(err)
  15. })

二:Generator

  1. function* fn(a){
  2. var x=yield a;
    //x==4
  3. var y=yield x;
  4. var z=yield y+1;
  5. }
  6. var demo=fn(1)
  7. console.log(demo.next(2))//{ value: 1, done: false }
  8. console.log(demo.next(3))//{ value: 3, done: false }
  9. console.log(demo.next(4))//{ value: 5, done: false }
  10. console.log(demo.next(5))//{ value: undefined, done: true }

generator 函数和普通函数不通之处在与function后面需要加一个*,直接调用时不会执行,必须调用next方法才会执行。而且函数内部可以有多个yield即可以返回多个值。有点类似打断点,调用一次next方法执行一步。

yield默认没有返回值,可以在调用next时加入参数作为上一个yield的返回值

上面的例子给fn函数传入1,此时不执行,

调用第一个next方法,此时a==1,此时无返回值,value==1

调用第二个next方法传入3,即x==3,value==3

调用第三个next传入4 即y==4  value==4+1==5

再次调用next方法 generator执行完毕,所以value为undefined done为true

三:co

co是express和koa的作者tj大神基于es6 Generator和promise实现的一个解决js异步回调嵌套地狱的库除了注视100行左右代码,可谓短小精悍。

co允许我们像写同步代码一样鞋异步代码,并且可以用try catch捕获异常。调用co始终返回一个promise所以也可以用then catch。 使用方法如下(传入一个generator function)

注:function* (){}()是generator

function* (){}是generator function

  1. co(function*() {
  2. try {
  3. var a = readFile('01.txt');
  4. var b = readFile('02.txt');
  5. var c = readFile('03.txt');
  6. //yield后面可以跟对象、数组、promise、Thunks、Generators、Generator Functions
  7. var res = yield [a, b, c];
  8. return res;
  9. } catch (err) {
  10. console.error(err.message); // "boom"
  11. }
  12. })
  13. .then(function(data) {
  14. console.log(data)
  15. })
  16. .catch(function(error) {
  17. console.log(error)
  18. });

四:co源码

1.调用co始终返回一个promise,这也是co后面也可以跟then catch的原因

2.co的核心就是通过next方法不断调用 generator的next方法,直到generator执行完毕。

3.yield 后面个跟以下几种function, promise, generator, array, or object,然后调用toPromise方法将以上几种数据格式都转化为promise

核心代码如下

4.可以通过co.wrap把一个generator函数转化为promise,原理是co.wrap内部调用了co函数,因为co始终返回一个promise,所以co.wrap可以将generator函数转化为promise。

另外如果需要调用两个除了参数不同其余都相同的co,此时可以用co.wrap()返回普通函数带入实参调用。如下

  1. var getFile = co.wrap(function* (file){
  2. var filename = yield readFile(file, 'utf-8');
  3. return filename;
  4. });
  5. getFile('./01.txt')
  6. .then(function(data){
  7. console.log(data)
  8. })
  9. getFile('./02.txt')
  10. .then(function(data){
  11. console.log(data)
  12. })

5.co函数如下

  1. function co(gen) {
  2. //这里的this在node中指向global
  3. var ctx = this;
  4. var args = slice.call(arguments, 1)
  5. //返回一个promise对象
  6. return new Promise(function(resolve, reject) {
  7. //如果gen为一个generator function则执行函数返回一个generator对象
  8. //相当于执行function* (){}()
  9. if (typeof gen === 'function') gen = gen.apply(ctx, args);
  10. //如果gen为空或者不是generator function则直接把gen放在promise的resolve中作为参数
  11. if (!gen || typeof gen.next !== 'function') return resolve(gen);
  12. //默认调用一次onFulfilled
  13. onFulfilled();
  14. function onFulfilled(res) {
  15. console.log(res)
  16. var ret;
  17. try {
  18. //第一次调用next不传参数
  19. ret = gen.next(res);
  20. } catch (e) {
  21. return reject(e);
  22. }
  23. //递归yeild
  24. next(ret);
  25. }
  26. //如果yeild后面跟的不是function, promise, generator, array, or object
  27. //的一种,则执行这里。
  28. function onRejected(err) {
  29. var ret;
  30. try {
  31. ret = gen.throw(err);
  32. } catch (e) {
  33. return reject(e);
  34. }
  35. next(ret);
  36. }
  37. function next(ret) {
  38. console.log(ret)
  39. //如果generator function执行完毕,直接返回数据(undefined)
  40. if (ret.done) return resolve(ret.value);
  41. //generator function没有执行完毕,把所有ret.value转化为promise
  42. var value = toPromise.call(ctx, ret.value);
  43. //如果转换为promise成功则执行promise
  44. //yeild后面只能跟function, promise, generator, array, or object
  45. if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
  46. //转换失败则抛出错误
  47. return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
  48. + 'but the following object was passed: "' + String(ret.value) + '"'));
  49. }
  50. });
  51. }

其余就是一系列的数据结构抓换为ptomise

  1. //数组转化为promise,对数组用map遍历,然后把每一项转换为promise。
  2. //promise的all可以传入多个promise,并返回一个新的ptomise
  3. //所有子promise执行完毕后,这个promise才进入resolve
  4. function arrayToPromise(obj) {
  5. return Promise.all(obj.map(toPromise, this));
  6. }
  1. //对象转换为promise
    function objectToPromise(obj){
  2. //新建一个空obj
  3. var results = new obj.constructor();
  4. //返回一个obj的键数组
  5. var keys = Object.keys(obj);
  6. //这个空数组用于存放对象中所有值转换完的promise
  7. var promises = [];
  8. //循环便利每一项,调用toPromise
  9. for (var i = 0; i < keys.length; i++) {
  10. var key = keys[i];
  11. var promise = toPromise.call(this, obj[key]);
  12. //如果转换成为promise则push到promises
  13. if (promise && isPromise(promise)) defer(promise, key);
  14. else results[key] = obj[key];
  15. }
  16. //Promise.all执行所有的promise然后返回一个新的promise
  17. return Promise.all(promises).then(function () {
  18. return results;
  19. });
  20.  
  21. function defer(promise, key) {
  22. results[key] = undefined;
  23. promises.push(promise.then(function (res) {
  24. results[key] = res;
  25. }));
  26. }
  27. }

目前理解还不是特别深刻,以后有了新的理解随时补上。

参考文章  (1)阮老师es6入门

(2)搞定 koa 之 co源码

(3)co-4.0新变化

Generator库co4.6使用及源码分析的更多相关文章

  1. Koa源码分析(一) -- generator

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: 1. Koa源码分析(一) -- generator 2. Koa源码分析(二) -- co的实现 ...

  2. [转]数据库中间件 MyCAT源码分析——跨库两表Join

    1. 概述 2. 主流程 3. ShareJoin 3.1 JoinParser 3.2 ShareJoin.processSQL(...) 3.3 BatchSQLJob 3.4 ShareDBJo ...

  3. 比特币源码分析--C++11和boost库的应用

    比特币源码分析--C++11和boost库的应用     我们先停下探索比特币源码的步伐,来分析一下C++11和boost库在比特币源码中的应用.比特币是一个纯C++编写的项目,用到了C++11和bo ...

  4. Hadoop2源码分析-YARN 的服务库和事件库

    1.概述 在<Hadoop2源码分析-YARN RPC 示例介绍>一文当中,给大家介绍了YARN 的 RPC 机制,以及相关代码的演示,今天我们继续去学习 YARN 的服务库和事件库,分享 ...

  5. 从Generator入手读懂co模块源码

    这篇文章是讲JS异步原理和实现方式的第四篇文章,前面三篇是: setTimeout和setImmediate到底谁先执行,本文让你彻底理解Event Loop 从发布订阅模式入手读懂Node.js的E ...

  6. 从源码分析node-gyp指定node库文件下载地址

    当我们安装node的C/C++原生模块时,涉及到使用node-gyp对C/C++原生模块的编译工作(configure.build).这个过程,需要nodejs的头文件以及静态库参与(后续称库文件)对 ...

  7. Redis网络库源码分析(1)之介绍篇

    一.前言 Redis网络库是一个单线程EPOLL模型的网络库,和Memcached使用的libevent相比,它没有那么庞大,代码一共2000多行,因此比较容易分析.其实网上已经有非常多有关这个网络库 ...

  8. Koa源码分析(二) -- co的实现

    Abstract 本系列是关于Koa框架的文章,目前关注版本是Koa v1.主要分为以下几个方面: Koa源码分析(一) -- generator Koa源码分析(二) -- co的实现 Koa源码分 ...

  9. 异步编程之co——源码分析

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

随机推荐

  1. Usaco*Monthly Expense

    Description Farmer John是一个令人惊讶的会计学天才,他已经明白了他可能会花光他的钱,这些钱本来是要维持农场每个月的正常运转的.他已经计算了他以后N(1<=N<=100 ...

  2. Node.js Ubuntu下安装

    安装 Node.js 依次执行以下指令: sudo apt-get update sudo apt-get install -y python-software-properties python g ...

  3. wpf之mvvm基类

    当我们用MVVM设计模式的时候要实现INotifyPropertyChanged,每次都要实现这个接口比较麻烦,所以基类的作用就体现出来了.代码如下:   1 2 3 4 5 6 7 8 9 10 1 ...

  4. Android Support Library

    title: Android Support Library tags: Support Library,支持库 grammar_cjkRuby: true --- DATE: 2016-5-13. ...

  5. (翻译)《Hands-on Node.js》—— Why?

    事出有因 为何选择event loop? Event Loop是一种推进无阻塞I/O(网络.文件或跨进程通讯)的软件模式.传统的阻塞编程也是用一样的方式,通过function来调用I/O.但进程会在该 ...

  6. 【腾讯Bugly干货分享】WebP原理和Android支持现状介绍

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/582939577ef9c5b708556b0d 1.背景 目前网络中图片仍然是占 ...

  7. 使用ReSharper打造团队代码检查流程

    首先我想跟大家分享一下我们团队的代码检查流程. 1. 项目经理随时会检查成员的代码,如果发现有不符合规范的代码,会在注释里面加todo.比如,假设leo的代码不符合规范,那么项目经理就会加注释: // ...

  8. Java 8函数编程轻松入门(二)Stream的使用

    在C#中,微软基于IEnumerable接口,提供许多便捷的扩展方法,便于实际的开发.在Java 1.8中,Collection接口新增了default stream方法.我们可以针对java集合,在 ...

  9. 编译异常 Caused by: java.lang.UnsupportedClassVersionError:

    Caused by: java.lang.UnsupportedClassVersionError: com/sumingk/platform/service/impl/ServiceSysPerso ...

  10. Windows组件:打开MSDTC,恢复Windows TaskBar,查看windows日志,打开Remote Desktop,打开Services,资源监控

    一,Win10 打开 MSDTC 1,Win+R 打开运行窗口,输入 dcomcnfg,打开组件服务窗口 2,在组件服务 catalog下找到 Distributed Transaction Coor ...