Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

koa源码分析(五) - koa 2.0 #10

Open
brunoyang opened this issue Nov 7, 2015 · 1 comment
Open

koa源码分析(五) - koa 2.0 #10

brunoyang opened this issue Nov 7, 2015 · 1 comment

Comments

@brunoyang
Copy link
Owner

co的README里,tj写道co是async/await的一块垫脚石,没想到好时代这么快就来了,我们已经可以借助babel写出形似同步的异步代码了(需开启experimental模式)。而借着这股春风,koa2.0也来了。

我们还是先来看一下什么是async/await函数吧。

async函数就是generator + promise,只不过是将yield换成了await,但是比yield好理解,并且不用next来显式地执行下一步。async 可以声明一个异步函数,此函数需要返回一个 Promise 对象。await 可以等待一个 Promise 对象 resolve,并拿到结果。我们来看一个例子(引用自阮一峰老师的ECMAScript 6 入门)。

const readFile = function (fileName){
  return new Promise(function (resolve, reject){
    fs.readFile(fileName, function(error, data){
      if (error) reject(error);
      resolve(data);
    });
  });
};

const asyncReadFile = async function (){
  const f1 = await readFile('a.txt');
  const f2 = await readFile('b.txt');
  console.log(f1.toString());
  console.log(f2.toString());
};

可以看到,async和promise是紧密结合在一起的,await的结果就是被修饰函数的resolve值,那似乎没有方法接收reject呀,所以,最好是将await包裹在try/catch中,用来接收reject。

const asyncReadFile = async function (){
  try{
    const f1 = await readFile('a.txt');
    const f2 = await readFile('b.txt');
    console.log(f1.toString());
    console.log(f2.toString());
  } catch(e) {
    console.log('failed!');
  } 
};

有了async,能让我们更好地书写异步代码,就是这么的方便。

说了这么多async,我们再来看koa。koa2.0相对于1.0,转变体现在将var换成了let及const,使用箭头函数简化书写,不再支持generator,以及对于中间件的处理上。

中间件有一个很形象的比喻,就像一个洋葱,一个请求从最外面那一层进入洋葱,一路上进过一层层的中间件,到达洋葱心之后,请求完成了任务,又派了响应出去,带上需要返回的数据,一层层地返回最外面。而在进入出来的过程中,中间件会对请求和响应做『手脚』,比如对请求检验cookie,对响应加etag。那中间件是怎么知道来的到底是请求还是响应呢?其实中间件不需要知道,这是因为请求肯定早于响应,所以koa的中间件的做法就是将函数的上半部分用来处理请求,下半部分用来处理响应(这里只是打比方)。而区分『上半部分』和『下半部分』的分界线,在1.0是yield next(),在2.0中,就是await next()或是return next().then()。

说完原理,再来看koa-compose,最关键的只有一步

return Promise.resolve(fn(context, function next() {
  return dispatch(i + 1)
}))

Promise.resolve的作用是将一个普通的对象转换成promise对象,防止上一步放回一个普通函数,造成中间件链路的断裂。

为了更好地理解如何使用中间件,我们来写一个访客记录的中间件。

首先分析一下需求,我们认为请求中带有visited字段cookie的请求是来自曾经访问过本网站的游客,就在数据库中增加一次访问量,并将该条请求打个标记便于后续操作。若没有visitedcookie,就在响应增加visitedcookie。

module.exports = async function (ctx, next) {
  ctx.countNum = await count();
  const visited = ctx.cookies.get('visited') ? true : false;

  await next();

  if (!visited) {
    setCookie(ctx, 'visited');
  }
}

function count() {
  const Count = new mongoose.model('count');

  Count.add()
  .then(function() {
    return Count.findCountNum();
  })
  .then(function(num) {
    return Promise.reslove(num);
  });
} 

function setCookie(ctx, name) {
  ctx.cookies.set(name, 'what ever');
}
@Seven0711
Copy link

简直帮大忙了,太流弊了(づ ̄3 ̄)づ╭❤~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants