koa源码阅读之context.js/koa-convert/is-generator-function
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: '<original node req>', res: '<original node res>', socket: '<original node 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
看完全文都是好样的!!
相关推荐
瓜牛呱呱 2020-11-12
柳木木的IT 2020-11-04
yifouhu 2020-11-02
lei0 2020-11-02
源码zanqunet 2020-10-28
源码zanqunet 2020-10-26
一叶梧桐 2020-10-14
码代码的陈同学 2020-10-14
lukezhong 2020-10-14
lzzyok 2020-10-10
anchongnanzi 2020-09-21
clh0 2020-09-18
changcongying 2020-09-17
星辰大海的路上 2020-09-13
abfdada 2020-08-26
mzy000 2020-08-24
shenlanse 2020-08-18
zhujiangtaotaise 2020-08-18
xiemanR 2020-08-17