Giter Site home page Giter Site logo

co-and-koa-talk's Introduction

title: Generator, Co and Koa

author:

name: dead_horse

url: https://github.com/dead-horse

output: index.html

controls: false

--

--

generator

  • ES6 新特性
  • node v0.11 可以使用 (node --harmony)
  • 通过 gnode 体验

--

function* hello() {
  yield 'hello';
  yield function () {
    return 'generator';
  };
  return 'done';
}
> hello.constructor.name // GeneratorFunction
> var gen = hello();
> typeof gen.next === 'funciton';
> typeof gen.throw === 'function';

> var res = gen.next();
> res.value === 'hello';
> res = gen.next();
> res.value() === 'generator';
> res = gen.next();
> res.value === 'done';
> res.done = true;

--

function* fibonacci(total) {
  var first = 0;
  var second = 1;
  var tmp;

  yield first;
  yield second;

  while(total--) {
    tmp = first;
    first = second;
    second = tmp + second;
    yield second;
  }
}

--

generator 与异步

--

yield 异步方法

function delay(done) {
  setTimeout(function () {
    done(null, 'delay done');
  }, 1000);
}

function *genFn() {
  console.log('before delay');
  console.log(yield delay);
  console.log('after delay');
}

var gen = genFn();
next();

function next(err, res) {
  var ret = gen.next(res);
  if (!ret.done) {
    return ret.value(next);
  }
}

full example

--

yieldable and thunk

  • 只接受一个参数(且为callback)的异步函数
  • 需要将所有的 callback 形式的方法都转换成 thunk
function delay(interval) {
  // 返回的是一个 thunk
  return function (done) {
    setTimeout(function () {
      done(null, 'delay done');
    }, interval);
  };
}
yield delay(1000);

--

callback to thunk

fs.stat(filename, callback);

// =>

function stat(filename) {
  return function (done) {
    fs.stat(filename, done);
  }
}

// =>

function *() {
  yield stat('./README.md');
}

--

promise to thunk

function (promise) {
  return function (fn) {
    promise.then(funciton (res) {
      fn(null, res);
    }, fn);
  }
}

--

function arrayToThunk(array) {
  return function (done) {
    var called = false, len = array.length, result = [];
    // 同时并发的执行 array 里面的异步函数
    // 异步函数执行完调用 cb
    // cb 调用 `array.lenth` 次之后执行 done
    // 这样把一个函数的数组转换成了一个 thunk
    array.forEach(function (fn, index) {
      fn(function (err, data) {
        if (err) return cb(err);
        result[index] = data;
        cb();
      });
    });
    // cb 执行 `len` 次之后才会执行 done()
    var cb = function (err) {
      if (called) return;
      if (err) {
        called = true;
        return done(err);
      }
      if (--len === 0) {
        called = true;
        done(null, result);
      }
    };
  };
}

--

  • 基于 generator 的异步编程
var thunkify = require('thunkify');
var co = require('co');
var fs = require('fs');

var stat = thunkify(fs.stat);
var readFile = thunkify(fs.readFile);

co(function *() {
  var stat = yield stat('./README.md');
  var content = yield readFile('./README.md');
})();

--

原理

  • 可以被 yield 的有: thunk, promise, generator, generatorFunction, object, array

  • 所有的 node 形式的 callback 都需要转换成 thunk

  • object,array,promise 自动识别并转换成 thunk

  • generator, generatorFunction 自动识别并展开执行

--

series and parallel

  • series
co(function *() {
  var a = yield request(a);
  var b = yield request(b);
})();
  • parallel
co(function *() {
 var res = yield [request(a), request(b)];
})();

--

基于 co 的流程控制

  • co-parallel: 控制并发的 parallel
  • co-gather: 获取所有返回结果和错误的 parallel
  • co-wait: setTimeout 的 generator 版本
  • ...

--

  • 把 generator 代码编译成 ES5 的代码
  • 可以实现基于 generator 的编写的库的向下兼容
  • 但是需要保证所有的依赖(dependencies) 都是向下兼容(非 generator 或者支持转换)的
  • Examples

--

  • TJ 和 express 团队的新作品
  • 基于 generator 和 co 的异步解决方案
  • setter / getter 带来了更方便的 http 辅助方法
  • 更人性化的错误处理
  • 更灵活的中间件形式

--

koa VS express

  • 不提供默认路由

  • 不提供默认的模版渲染

  • 不支持 node 原生的 request 和 response

  • 不支持 express 中间件

  • 提供默认的异步解决方案(generator)

  • 更有表现力的中间件形式

  • 对 request / response 提供更好体验的中间件

--

Hello world

var koa = require('koa');
var app = koa();

app.use(function *() {
  this.body = 'hello!';
});

app.listen(7001);

--

中间件

middleware

--

function *responseTime() {
  var start = Date.now();
  yield next;
  var use = Date.now() - start;
  this.set('X-ResponseTime', use);
}

更灵活的中间件形式

var koa = require('koa');
var ejs = require('koa-ejs');
var app = koa();

ejs(app, {/*options*/});
// 挂载 function* render() {} 在 context.prototype上

app.use(function* () {
  return yield this.render('index');
});

--

更简洁的中间件实现方式

--

koa 中的异步

var fs = require('co-fs');

app.use(function *(){
  var paths = yield fs.readdir('docs');

  // parallel
  var files = yield paths.map(function(path){
    return fs.readFile('docs/' + path, 'utf8');
  });

  this.type = 'markdown';
  this.body = files.join('');
});

--

异常处理

  • 通过 try catch 来捕获所有的异常
  • 所有 throw 出去的 error 都会被 koa 捕获到
app.use(function *() {
  try {
    var file = yield fs.readFile('./README.md');
  } catch (err) {
    if (err.code === 'ENOENT') {
      this.status = 404;
      this.body = 'can not found readme'
      return;
    };
    throw err;
  }
});

--

Stream 的异常处理

  • 原生 http server 和 express 中
http.createServer(function (req, res) {
  var stream = fs.createReadStream('filename.txt');
  stream
  .on('error', onerror)
  .pipe(zlib.createGzip())
  .on('error', onerror)
  .pipe(res);

  function onerror(err) {
    res.statusCode = 500;
    res.end(err.message);
    console.error(err.stack);
  }

  res.once('close', function () {
    // 如果客户端终止了这个响应,可能导致 `fd` 泄漏, 需要 `unpipe` 来让它关闭这个 `fd`
    stream.unpipe();
  });
});

--

  • koa 中通过神奇的 this.body= 帮你处理 Stream 的各种坑
    • 不用担心 fd leak
    • 不用负责监听 error
app.use(function *() {
  this.body = fs.createReadStream('filename.txt');
  this.body = this.body.pipe(zlib.createGzip());
});

--

深入理解 koa 福利

--

基于 koa 的应用

  • cnpmjs.org - Private npm registry and web for Enterprise, base on koa, MySQL and Simple Store Service.
  • simgr - Image proxy and resizing server
  • component-crawler - component.json crawler

--

更多中间件

--

connect / experss 向 koa 迁移

  • 框架配置和中间件替换
  • model(proxy) 层通过 thunkify 或者 thunkify-wrap 包装
  • 改写 controllers
  • [进一步改写 model 层]

--

基于 co 的单元测试

  • mocha 开启选项: --harmony
  • mocha 添加依赖:--require co-mocha
$ mocha --harmony --require co-mocha

it('should co work fine', function *() {
  var stat = yield fs.stat('./README.md');
  var content = yield fs.readFile('./README.md');
  assert(stat.size === content.length);
});

--

推荐关注

--

Q & A

co-and-koa-talk's People

Contributors

dead-horse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

co-and-koa-talk's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.