koa中的异常处理

最后更新于:2022-04-01 22:07:15

# koa中的异常处理 比如router中某个yield可能抛错,这种情况下要返回请求是怎么做的呀,都是直接在app on error里面处理吗 在route里 ``` co(function* () { var result = yield Promise.resolve(true); return result; }).then(function (value) { console.log(value); }, function (err) { // 异常处理 console.error(err.stack); }); ```
';

如何知道require模块的用法

最后更新于:2022-04-01 22:07:13

# 如何知道require模块的用法 比如 ``` var router = require('koa-router')(); ``` 打开 https://www.npmjs.com/search?q=koa-router 找到 https://www.npmjs.com/package/koa-router
';

如何发布本书到git pages

最后更新于:2022-04-01 22:07:10

# gitbook发布说明 本书以gitbook为编辑器,发布到git pages上,为了便于大家使用,请按照如下办法生成并发布。 ## 下载gitbook编辑器 https://www.gitbook.com/editor ## 生成html > gitbook -> Book -> Preview Website ![](img/gitbook-preview.png) ## 发布到git pages上 ```shell gulp deploy ``` ## 预览并确认 访问 http://base-n.github.io/koa-generator-examples/
';

FAQ

最后更新于:2022-04-01 22:07:08

# faq
';

最佳实践

最后更新于:2022-04-01 22:07:06

# 最佳实践
';

部署

最后更新于:2022-04-01 22:07:04

# deploy
';

Supertest

最后更新于:2022-04-01 22:07:01

# supertest
';

Mocha

最后更新于:2022-04-01 22:06:59

# mocha
';

测试

最后更新于:2022-04-01 22:06:57

# test
';

promise with bluebird

最后更新于:2022-04-01 22:06:55

# promise with bluebird
';

async/await

最后更新于:2022-04-01 22:06:52

# async/await
';

co = generator + promise

最后更新于:2022-04-01 22:06:50

# co 理解了co的核心代码就理解了koa的流程控制 ```js var ctx = this; var args = slice.call(arguments, 1); ``` 一开始保存上下文,把arguments的length属性去掉,剩余的参数转数组就是gen的参数 再来看return的promise内的代码 ```js if (typeof gen === 'function') gen = gen.apply(ctx, args); if (!gen || typeof gen.next !== 'function') return resolve(gen); ``` 先判断gen是不是generator function,如果是就转为generator,相当于```gen = new gen;``` 转为generator之后就可以调用gen.next()了; ``` onFulfilled(); ``` 这是进入循环调用链的入口 ```js function onFulfilled(res) { var ret; try { ret = gen.next(res); } catch (e) { return reject(e); } next(ret); } function onRejected(err) { var ret; try { ret = gen.throw(err); } catch (e) { return reject(e); } next(ret); } function next(ret) { if (ret.done) return resolve(ret.value); var value = toPromise.call(ctx, ret.value); if (value && isPromise(value)) return value.then(onFulfilled, onRejected); return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, ' + 'but the following object was passed: "' + String(ret.value) + '"')); } ``` ret是gen.next后的{value:''done:''}对象,value是yield后的表达式,done是执行状态. 判断ret.done是否为true来确定是否需要再执行下去.为true时,说明已经是generator的最后一步,promise转为resolve.不为true时,将yield后的表达式转化为promise. 先判断是否转化为了promise,转化成功,就通过```value.then(onFulfilled, onRejected)```执行onFulfilled或onRejected,再次调用next(),实现循环调用. 当value不能转为promise时,抛出错误,promise转为reject,停止继续运行. 下面写一个例子简单分析一下: ```js var co = require('co'); var fs = require('fs'); function thunkRead(name) { return function (cb) { fs.readFile(name, function (err, file) { cb(err, file); }); } } co(function *() { var file = yield thunkRead("package.json"); console.log(file); return file; }).then(function (file) { console.log(file); }); ``` 通过上面这段代码来看一下co的整个流程 先模拟一个名为thunkRead的thunk函数,再看co里面的代码,co里面是一个generator function,```gen = gen.apply(ctx, args);``` 通过这一句转化为了generator。 再进入onFulfilled()函数,第一个gen.next()之后ret是 ```{ value: [Function], done: false }``` 将ret传入next()中,done为false,所以toPromise,value是function,所以thunkToPromise. ```js function thunkToPromise(fn) { var ctx = this; return new Promise(function (resolve, reject) { fn.call(ctx, function (err, res) { if (err) return reject(err); if (arguments.length > 2) res = slice.call(arguments, 1); resolve(res); }); }); } ``` 因为fn是thunk函数,参数只有一个回调函数, ```fn.call(ctx, function (err, res) {});``` 直接调用resolve,在上面的例子中是resolve(file); 然后回到next()中,此时已经是一个promise对象,调用value的then方法,onFulfilled的参数就是file,再运行gen.next(file),将上一步yield的结果file传入generator,因为在例子中最后return了file, ret是 ```{ value:, done: true }``` 最后不返回值的话应该是 ```{ value: undefined, done: true } ``` , 再进入到next()中, 此时done已经为true,说明已经是generator的最后一步,resolve(value); co中的代码已经执行结束,因为co也是一个promise, 最后resolve(value),所有可以在then方法中得到这个value. 补充下toPromise支持转化thunks,array,objects,generators,generator functions. 所以可以yieldable的是以下6种: - promises - thunks (functions) - array (parallel execution) - objects (parallel execution) - generators (delegation) - generator functions (delegation)
';

es6的generator是什么?

最后更新于:2022-04-01 22:06:48

# es6的generator是什么? generator指的是 ``` function* xxx(){ } ``` 是es6里的写法。 ``` function* test() { console.log('1'); yield 1; console.log('2'); yield 2; console.log('3'); } ``` 代码中间插了两行yield,代表什么呢? - 当test执行到 yield 1这一行的时候,程序将被挂起,要等待执行下一步的指令; - 当接收到指令后,test将继续往下运行,直到yield 2这一行,然后程序又被挂起并等待指令; - 收到指令后,test又将继续运行,而下面已经没有yield了,那么函数运行结束。 这是不是就像,我们调试代码的时候,给插的断点 ? 当然,断点这个比喻,只是表象上比较相像,实质原理还是有非常大差异。 yield就是让后面的generator执行完成后,才继续往下走。 要注意,function后面多了一个星号,这样是表明这个函数将变成一个生成器函数,而不是一个普通函数了。意思就是,test这个函数,将不能被这样执行 test(); 但可以获得一个生成器 var gen = test(); // gen就是一个生成器了 然后,生成器可以通过next()来执行运行 gen.next(); 也就是上面说的,让函数继续运行的指令。 简单地总结一下: - 生成器通过yield设置了一些类似”断点“的东西,使得函数执行到yield的时候会被阻断; - 生成器要通过next()指令一步一步地往下执行(两个yield之间为一步); - yield 语句后面带着的表达式或函数,将在阻断之前执行完毕; - yield 语句下面的代码,将不可能在阻断之前被执行; 由此可以看出,yield是如何将异步非阻塞代码,变成 异步阻塞代码。
';

generator/co

最后更新于:2022-04-01 22:06:46

# generator/co
';

流程控制

最后更新于:2022-04-01 22:06:43

# 流程控制 ![](img/cb.png) http://www.ruanyifeng.com/blog/2015/05/async.html
';

Mongo

最后更新于:2022-04-01 22:06:41

# mongodb
';

MySQL

最后更新于:2022-04-01 22:06:39

##封装思路 koa依赖co,其中间件对非阻塞异步代码的要求必须是Yieldables列表中的形式,而mysql库是回调函数的形式。因此,我们需要进行封装,使其接口符合要求。 目前我找到了四种方法,前三种使用开源库,第四种自己动手,将express下的dbHelper层封装成co最新支持的Promise形式。 ##实现方法一(co-mysql) co-mysql和mysql-co实现了对mysql或mysql2的封装转化。这两个库的思路差不多,mysql-co封装度更高,并使用速度更快的mysql2;而co-mysql更简单,只是将mysql.query封装成Promise形式。下面是基于co-mysql的示例代码: ``` var wrapper = require('co-mysql'), mysql = require('mysql'); var options = { /* 数据库连接字串 */ }; var pool = mysql.createPool(options), p = wrapper(pool); ... var rows = yield p.query('SELECT 1'); yield this.render('index', { title: rows[0].fieldName }); ... })(); ``` ##实现方法二(promisify-node) 使用promisify-node库,可以将库整体转化为Promise形式,也可以方便的转化库中的指定接口函数,示例代码如下: ``` var promisify = require("promisify-node"); var db = promisify("dbHelper"); //express下的回调形式封装库 ... var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName }); ... ``` ##实现方法三(thunkify) 使用thunkify也能够完成封装,thunkify-wrap是一个增强版的thunkify。不过看说明,这种方法在未来的发展中可能会被淘汰,大概的使用方法如下: ``` var genify = require('thunkify-wrap').genify; var db = genify("dbHelper"); //express下的回调形式封装库 ... var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName }); ... ``` ##实现方法四(直接方法) 直接改造原来express下的回调方式代码为Promise形式,代码及说明如下: dbHelper.js ``` var options = { /* 数据库连接字串 */ }; var mysql = require('mysql'); var pool = mysql.createPool(options); //原有非接口代码,对mysql的封装,执行sql语句 function execQuery(sql, values, callback) { var errinfo; pool.getConnection(function(err, connection) { if (err) { errinfo = 'DB-获取数据库连接异常!'; throw errinfo; } else { var querys = connection.query(sql, values, function(err, rows) { release(connection); if (err) { errinfo = 'DB-SQL语句执行错误:' + err; callback(err); } else { callback(null,rows); //注意:第一个参数必须为null } }); } }); } function release(connection) { try { connection.release(function(error) { if (error) { console.log('DB-关闭数据库连接异常!'); } }); } catch (err) {} } //对外接口代码,包装成返回Promise函数的形式 exports.getById = function(tablename, id){ return new Promise(function(resolve, reject){ var values = {id:id}; var sql = 'select * from ?? where ?'; execQuery(sql,[tablename, values], function(err, rows){ if(err){ reject(err); }else{ resolve(rows); } }) }); } ``` routes/index.js ``` var db = require("../dbHelper"); ... var rows = yield db.getById('tableName', {id:1}); yield this.render('index', { title: rows[0].fieldName }); ... ``` ##代码 示例部分代码取自该项目: ``` https://github.com/zhoutk/koadmin.git ``` ##小结 koa框架以co库为核心组织,很好的用generator来解决了回调函数问题。进行Promise接口形式包装的时候,要注意:回调函数要完全符合其要求的形式: ``` function(err, rows){ if(err){ reject(err); }else{ resolve(rows); } }) ```
';

数据库

最后更新于:2022-04-01 22:06:37

# db
';

Post with raw

最后更新于:2022-04-01 22:06:34

# Post with raw(todo) To get the raw body content of a request with Content-Type: "text/plain" into req.rawBody you can do: https://gist.github.com/tj/3750227 req.rawBody已经被干掉了,现在只能用req.text 下面是tj给出的代码片段 ```javascript var express = require('./') var app = express(); app.use(function(req, res, next){ if (req.is('text/*')) { req.text = ''; req.setEncoding('utf8'); req.on('data', function(chunk){ req.text += chunk }); req.on('end', next); } else { next(); } }); app.post('/', function(req, res){ res.send('got "' + req.text + '"'); }); app.listen(3000) ``` 测试 ```shell $ npm test ``` 使用Postman测试 ![](img/post-rawdata.png)
';

文件上传(Post with form-data)

最后更新于:2022-04-01 22:06:32

# 文件上传 Post with form-data 主要目的是为了上传 koa-v1 要是用 koa-multer-v0.0.2 对应的 multer < 1,所以本处需要指定版本安装 ```shell $ npm install --save koa-multer@0.0.2 ``` Usage ```javascript var app = require('koa')() , koa = require('koa-router')() , logger = require('koa-logger') , json = require('koa-json') , views = require('koa-views') , onerror = require('koa-onerror'); var multer = require('koa-multer'); app.use(multer({ dest: './uploads/'})); ``` You can access the fields and files in the request object: ```javascript router.post('/post/formdata', function *(next) { console.dir(this.req.body) console.dir(this.req.files) this.body = 'this a users response!'; }); ``` 重要提示: Multer will not process any form which is not multipart/form-data [see more](https://github.com/koa-modules/multer) 测试 ```shell $ npm test ``` 使用Postman测试 ![](img/post-formdata.png)
';