zoukankan      html  css  js  c++  java
  • Koajs原理

    本文地址 http://www.cnblogs.com/jasonxuli/p/5382090.html

    Koajs让习惯阻塞式代码写法的同学感到很舒服,再也不用盖楼式的callback了,而且也不需要学习Promise的then,catch这些新东西。

    但实际上,Koajs这样的写法有点像是语言的语法糖,它只不过把yield又包装成了Promise的链式调用。做这件事儿的库就是co库和compose库,compose库把koajs中的一堆中间件改装成了函数套娃,而co则把这些套娃改装成了Promise链。想要了解Koajs的原理,还真需要先了解一下Promise的基本概念。本文假设你已经了解了Promise的基本知识。

    koajs的用法大概是这样的:

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

    koa.use(function* m1(next){
         ...
         yield next;
         ...
    }
     
    koa.use(function* m2(next){
         ...
         yield next;
         ...
    }
     
    koa .listen(3000);
     
    这个koa.listen默认的callback是koa库的application.js中的app.callback,也就是在这个app.callback中,调用了关键的这一句:
    var fn = this.experimental
    ? compose_es7(this.middleware)
    : co.wrap(compose(this.middleware));
    这也引出了co库和compose库这两个koajs的核心库。
     
    先说compose库:
    koa.use函数关键的代码就是这一句 
    this.middleware.push(fn);
    也就是说这个this.middleware是个中间件的数组。
    实际上,compose是把[m1, m2, ...] 改装成了 m1(m2(m3(...))),以方便co库的下一步改装,如下:
     
    function compose(middleware){
      return function *(next){
        var i = middleware.length;
        var prev = next || noop();
        var curr;

        while (i--) {
          curr = middleware[i];            // curr = m3
          prev = curr.call(this, prev);   // m3.call(this, null)  >>> m3() 即 prev=m3()
        }
     
        yield *prev;                             // m3()
      }
    }
     
    最后的结果相当于返回了一个函数套娃:m1(m2(m3))
     
    这个结果作为co的参数,又发生了什么呢?
     
    co lib:
    Actually, co convert yields to promise thens.
     
    // fake codes
    function co(gen){
         if gen is a function
              gen = gen();
        
         if gen is null || gen is not a function
              return resolve(gen);
     
      onFulfilled();
     
         // onFulfilled() {
              try{
                   var ret = gen.next();
              }catch(){
                   reject(ret);
              }
        next();
         }
        
         // next() {
              if ret.done == true
                   return resolve(ret);
     
                   // toPromise(){
                   if ret is a general value
                        return resove(ret)
                   if ret is a generator   // 按深度延展: 处理 yield* 
                        return co(ret)
                   }
     
              if (isPromise(value))
                   return value.then(onFulfilled, onRejected);    // 按广度延展:处理下一个yield
         }
    }
     
    这段co代码去除了很多看起来稍稍复杂的细节,有利于捋清楚脉络。
     
    看明白co库和compose库,你就知道,koajs只是给了大家用同步阻塞方式写IO处理的自由,实际上它在背后偷偷的采用了Promise链式调用的方式。
    我刚开始了解koajs的时候,最大的疑问也正是这个:为什么一个异步非阻塞的语言可以用阻塞的方式处理异步的IO呢?
    现在这个问题有了答案。
     
    2015-11-16 于Evernote
     
     
     
  • 相关阅读:
    IOS提交审核 错误Missing Push Notification Entitlement
    IOS提交审核 Missing Info.plist key问题
    【转载】cocos2dx 3.x 声音播放、音量调节
    【乐畅】工作积累 ---- 后台倒计时 ( 体力恢复功能 )
    【乐畅】工作积累 ---- 时间获取各个方法
    【乐畅】工作积累 ---- 设置一个弹窗的层
    【转载】【cocos2dx】特效收集
    【转载】cocos2dx 3.1获取系统当前时间
    【转载】cocos2d-x类型转换(CCstring int string char UTF-8互转)以及字符串详解
    【转载】Cocos2dx 小技巧(十四)ScrollView实现缩放效果
  • 原文地址:https://www.cnblogs.com/jasonxuli/p/5382090.html
Copyright © 2011-2022 走看看