资讯专栏INFORMATION COLUMN

koa源码阅读之context.js/koa-convert/is-generator-functi

caikeal / 1421人阅读

摘要:老伙计今天我们来讲一下的还有一些自己写的库吧。我们常用来在中间件发出一些错误状态码。从而使得上级中间件可以这个错误从而响应默认的一个错误处理如果不是实例。看完全文都是好样的源码链接文档链接

hey 老伙计 今天我们来讲一下koa的context.js还有一些tj自己写的库吧。 context.js
"use strict";
const createError = require("http-errors");
const httpAssert = require("http-assert");
const delegate = require("delegates");
const statuses = require("statuses");

const proto = module.exports = {

    //前面文章有讲过这个了,这里不描述了
  inspect() {
    if (this === proto) return this;
    return this.toJSON();
  },

  toJSON() {
    return {
      request: this.request.toJSON(),//实际上调用request.js的toJSON(下同)
      response: this.response.toJSON(),
      app: this.app.toJSON(),
      originalUrl: this.originalUrl,
      req: "",
      res: "",
      socket: ""
    };
  },

  /**
   * Similar to .throw(), adds assertion.
   *
   *    this.assert(this.user, 401, "Please login!");
   *
   * See: https://github.com/jshttp/http-assert
   *
   * @param {Mixed} test
   * @param {Number} status
   * @param {String} message
   * @api public
   */

  assert: httpAssert,

  /**
   * Throw an error with `msg` and optional `status`
   * defaulting to 500. Note that these are user-level
   * errors, and the message may be exposed to the client.
   *
   *    this.throw(403)
   *    this.throw("name required", 400)
   *    this.throw(400, "name required")
   *    this.throw("something exploded")
   *    this.throw(new Error("invalid"), 400);
   *    this.throw(400, new Error("invalid"));
   *
   * See: https://github.com/jshttp/http-errors
   *
   * @param {String|Number|Error} err, msg or status
   * @param {String|Number|Error} [err, msg or status]
   * @param {Object} [props]
   * @api public
   */
    //throw方法。上面是使用的方法。我们 常用来在中间件throw发出一些错误状态码。
    //从而使得上级中间件可以try catch这个错误从而响应
    //createError([status], [message], [properties])
    //properties - custom properties to attach to the object
  throw(...args) {
    throw createError(...args);
  },
    //默认的一个错误处理
  onerror(err) {
    // don"t do anything if there is no error.
    // this allows you to pass `this.onerror`
    // to node-style callbacks.
    if (null == err) return;
    // 如果error不是Error实例。此时生成一个错误实例给下文处理
    if (!(err instanceof Error)) err = new Error(`non-error thrown: ${err}`);

    let headerSent = false;
    //当然需要可写且没有被发送
    if (this.headerSent || !this.writable) {
      headerSent = err.headerSent = true;
    }

    //触发事件
    this.app.emit("error", err, this);

    //发送了肯定啥都不能干了
    if (headerSent) {
      return;
    }

    const { res } = this;
    //解构一下获得response
    
    //兼容咯
    //首次清除所有的headers
    if (typeof res.getHeaderNames === "function") {
      res.getHeaderNames().forEach(name => res.removeHeader(name));
    } else {
      res._headers = {}; // Node < 7.7
    }

    // 然后设置为错误的headers标识
    this.set(err.headers);

    //强制text/plain
    this.type = "text";

    // 支持ENOENT 
    if ("ENOENT" == err.code) err.status = 404;

    // 默认转换成500状态码
    if ("number" != typeof err.status || !statuses[err.status]) err.status = 500;

    //响应
    const code = statuses[err.status];
    const msg = err.expose ? err.message : code;
    this.status = err.status;
    this.length = Buffer.byteLength(msg);
    this.res.end(msg);
    //跟原生的一样嘛。
    //给我们一个提示。我们要使一个连接关闭。那么ctx.res.end(msg);
  }
};

/**
 * Response delegation.
 */
//委托到这个上下文对象里
//委托方法 与属性的getter或者setter
delegate(proto, "response")
  .method("attachment")
  .method("redirect")
  .method("remove")
  .method("vary")
  .method("set")
  .method("append")
  .method("flushHeaders")
  .access("status")
  .access("message")
  .access("body")
  .access("length")
  .access("type")
  .access("lastModified")
  .access("etag")
  .getter("headerSent")
  .getter("writable");

/**
 * Request delegation.
 */

delegate(proto, "request")
  .method("acceptsLanguages")
  .method("acceptsEncodings")
  .method("acceptsCharsets")
  .method("accepts")
  .method("get")
  .method("is")
  .access("querystring")
  .access("idempotent")
  .access("socket")
  .access("search")
  .access("method")
  .access("query")
  .access("path")
  .access("url")
  .getter("origin")
  .getter("href")
  .getter("subdomains")
  .getter("protocol")
  .getter("host")
  .getter("hostname")
  .getter("URL")
  .getter("header")
  .getter("headers")
  .getter("secure")
  .getter("stale")
  .getter("fresh")
  .getter("ips")
  .getter("ip");

因为下一个篇幅准备将最重要的application.js
所以这个接下来准备说几个引入的库源码

koa convert 用于什么?用于将koa1的中间件转化为promise 看到co就应该有这么个想法了= =
"use strict"

const co = require("co")
//引入co
const compose = require("koa-compose")

module.exports = convert

function convert (mw) {
    //进行判断
  if (typeof mw !== "function") {
    throw new TypeError("middleware must be a function")
  }
  if (mw.constructor.name !== "GeneratorFunction") {
    // assume it"s Promise-based middleware
    return mw
  }
  const converted = function (ctx, next) {
    return co.call(ctx, mw.call(ctx, createGenerator(next)))
  }
  converted._name = mw._name || mw.name
  return converted
}

function * createGenerator (next) {
  return yield next()
}

// convert.compose(mw, mw, mw)
// convert.compose([mw, mw, mw])
// koa-compose 日后再说嘻嘻^v^
convert.compose = function (arr) {
  if (!Array.isArray(arr)) {
    arr = Array.from(arguments)
  }
  return compose(arr.map(convert))
}
//我的天啊。这个疯子还支持回退
//回退方法很是精妙啊
convert.back = function (mw) {
  if (typeof mw !== "function") {
    throw new TypeError("middleware must be a function")
  }
  if (mw.constructor.name === "GeneratorFunction") {
    // assume it"s generator middleware
    return mw
  }
  const converted = function * (next) {
    let ctx = this
    let called = false
    // no need try...catch here, it"s ok even `mw()` throw exception
    yield Promise.resolve(mw(ctx, function () {
        //使得next仅仅被调用一次
      if (called) {
        // guard against multiple next() calls
        // https://github.com/koajs/compose/blob/4e3e96baf58b817d71bd44a8c0d78bb42623aa95/index.js#L36
        return Promise.reject(new Error("next() called multiple times"))
      }
      called = true
      return co.call(ctx, next)
    }))
  }
  converted._name = mw._name || mw.name
  return converted
}
is-generator-function
"use strict";
//减少查找引用,常见的优化方法
var toStr = Object.prototype.toString;
var fnToStr = Function.prototype.toString;
//这个正则匹配function *但是好像有点bug
//* function(){}也会受到判定true
var isFnRegex = /^s*(?:function)?*/;

var hasToStringTag = typeof Symbol === "function" && typeof Symbol.toStringTag === "symbol";
var getProto = Object.getPrototypeOf;
var getGeneratorFunc = function () { // eslint-disable-line consistent-return
    if (!hasToStringTag) {
        return false;
    }
    try {
        return Function("return function*() {}")();
    } catch (e) {
    }
};
var generatorFunc = getGeneratorFunc();
var GeneratorFunction = generatorFunc ? getProto(generatorFunc) : {};

//主要从三点看。
//一点是function toString
//一点是[object GeneratorFunction] Object toString
//一点是从原型看(内部[[Prototype]]属性的值)
module.exports = function isGeneratorFunction(fn) {
    if (typeof fn !== "function") {
        return false;
    }
    if (isFnRegex.test(fnToStr.call(fn))) {
        return true;
    }
    if (!hasToStringTag) {
        var str = toStr.call(fn);
        return str === "[object GeneratorFunction]";
    }
    return getProto(fn) === GeneratorFunction;
};

这次写的好粗糙啊= =
希望在结尾部分能写好。
sry sry sry

看完全文都是好样的!!

koa源码链接

文档api链接

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85107.html

相关文章

  • koa源码阅读目录结构与辅助库相关

    摘要:从一个对象里面提取需要的属性这篇文章一直想写了还想起那一夜我看到白天的代码,实在太美了。 koa源码lib主要文件有 application.js context.js request.js response.js application.js koa主要的逻辑处理代码整个koa的处理 context.js 将req,res方法 挂载在这,生成ctx上下文对象 requests....

    sherlock221 评论0 收藏0
  • 超轻量级web框架koa源码阅读

    摘要:是一个非常轻量的框架,里面除了和之外什么都没有,甚至连最基本的功能都需要通过安装其他中间件来实现。而的源码同样很简洁,基础代码只有不到行,非常适合阅读学习。的源码直接从获取,本文采用目前最新的版本。 koa是一个非常轻量的web框架,里面除了ctx和middleware之外什么都没有,甚至连最基本的router功能都需要通过安装其他中间件来实现。不过虽然简单,但是它却非常强大,仅仅依靠...

    inapt 评论0 收藏0
  • Koa源码阅读笔记(2) -- compose

    摘要:于是抱着知其然也要知其所以然的想法,开始阅读的源代码。问题读源代码时,自然是带着诸多问题的。源代码如下在被处理完后,每当有新请求,便会调用,去处理请求。接下来会继续写一些阅读笔记,因为看的源代码确实是获益匪浅。 本笔记共四篇Koa源码阅读笔记(1) -- coKoa源码阅读笔记(2) -- composeKoa源码阅读笔记(3) -- 服务器の启动与请求处理Koa源码阅读笔记(4) -...

    roland_reed 评论0 收藏0
  • Koa源码阅读笔记(4) -- ctx对象

    摘要:本笔记共四篇源码阅读笔记源码阅读笔记源码阅读笔记服务器启动与请求处理源码阅读笔记对象起因前两天终于把自己一直想读的源代码读了一遍。首先放上关键的源代码在上一篇源码阅读笔记服务器启动与请求处理中,我们已经分析了的作用。 本笔记共四篇Koa源码阅读笔记(1) -- coKoa源码阅读笔记(2) -- composeKoa源码阅读笔记(3) -- 服务器の启动与请求处理Koa源码阅读笔记(4...

    ityouknow 评论0 收藏0
  • 如何阅读源码--Koa为例

    摘要:最近一年零零散散看了不少开源项目的源码多少也有点心得这里想通过这篇文章总结一下这里以为例前段时间其实看过的源码但是发现理解的有点偏差所以重新过一遍不得不说阅读的代码真的收获很大没啥奇技淫巧代码优雅设计极好注释什么的就更不用说了总之还是推荐把 最近一年零零散散看了不少开源项目的源码, 多少也有点心得, 这里想通过这篇文章总结一下, 这里以Koa为例, 前段时间其实看过Koa的源码, 但是...

    zhoutk 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<