栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

通过4个问题了解Koa原理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

通过4个问题了解Koa原理

目录

1. 通过koa()创建了什么

2. app.listen()是如何启动服务器的

3. app.use(中间件) 中间件放到了哪里

4. 用户发送了请求,中间件是如何被回调的


1. 通过koa()创建了什么
// application.js 删除了部分代码
module.exports = class Application extends Emitter {
  constructor(options) {
    super();
    options = options || {};
    this.proxy = options.proxy || false;
    this.subdomainOffset = options.subdomainOffset || 2;
    this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
    this.maxIpsCount = options.maxIpsCount || 0;
    this.env = options.env || process.env.NODE_ENV || 'development';
    if (options.keys) this.keys = options.keys;
    this.middleware = [];
    this.context = Object.create(context);
    this.request = Object.create(request);
    this.response = Object.create(response);

    if (util.inspect.custom) {
      this[util.inspect.custom] = this.inspect;
    }
  }
};

创建了一个继承自events的Application对象,在constructor中进行了许多初始化操作。

2. app.listen()是如何启动服务器的
// application.js中的class Application中的类方法listen
  listen(...args) {
    debug('listen');
    const server = http.createServer(this.callback());
    return server.listen(...args);
  }

调用application.js中的class Application中的类方法listen,本质上还是调用了http.createServer。

callback方法在下面的“用户发送了请求,中间件是如何被回调的”中详细介绍。

3. app.use(中间件) 中间件放到了哪里

// application.js中的class Application中的类方法use
  use(fn) {
    if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
    if (isGeneratorFunction(fn)) {
      deprecate('Support for generators will be removed in v3. ' +
                'See the documentation for examples of how to convert old middleware ' +
                'https://github.com/koajs/koa/blob/master/docs/migration.md');
      fn = convert(fn);
    }
    debug('use %s', fn._name || fn.name || '-');
    this.middleware.push(fn);
    return this;
  }

调用了application.js中的class Application中的类方法use,主要是将函数放入middleware这个数组中,等待被调用。

4. 用户发送了请求,中间件是如何被回调的

在listen中调用了callback函数。

// application.js中的class Application中的类方法listen
  listen(...args) {
    debug('listen');
    const server = http.createServer(this.callback());
    return server.listen(...args);
  }

让我们来看看callback方法。

// application.js中的class Application中的类方法callback
  callback() {
    const fn = compose(this.middleware);

    if (!this.listenerCount('error')) this.on('error', this.onerror);

    const handleRequest = (req, res) => {
      const ctx = this.createContext(req, res);
      return this.handleRequest(ctx, fn);
    };

    return handleRequest;
  }

将所有的中间件进行compose组合后传入handleRequest函数。

先来看看compose函数,它是从koa-compose中引入的。

// koa-compose/index.js
function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }

  

  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

在这个函数中返回dispatch(0)的执行结果(第一个中间件是需要程序中自动执行的,因为没有前一个next);

在dispatch函数中首先根据传入的 i 获得第i个中间件(i从0开始),并通过Promise.resolve包裹;

若用户调用了next函数,则会调用dispatch函数。

return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));

因此,compose函数主要的作用就是返回一个Promise,若用户调用了next函数,这个Promise会递归调用用户传入的中间件。

再让我们再回过头看一看callback函数中的handleRequest函数。

// application.js中的class Application中的类方法handleRequest
  handleRequest(ctx, fnMiddleware) {
    const res = ctx.res;
    res.statusCode = 404;
    const onerror = err => ctx.onerror(err);
    const handleResponse = () => respond(ctx);
    onFinished(res, onerror);
    return fnMiddleware(ctx).then(handleResponse).catch(onerror);
  }

主要就是执行compose所返回的Promise对象fnMiddleware。

以上,大概就是中间件被回调的过程。

参考资料:深入Node.js技术栈-学习视频教程-腾讯课堂

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1028947.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号