在KOA中使用callback与nodejs
最近我正在研究一个新的项目,这个项目在nodejs中使用JavaScriptcallback。 现在我们使用KOA,但是当我们尝试使用ES6生成器和callback函数时会发生问题。
//Calback function function load(callback){ result = null; //Do something with xmla4js and ajax callback(result); return result; }
现在在KOA我需要调用load
和响应JSON到客户端,所以我使用下面的代码:
router= require('koa-router'); app = koa(); app.use(router(app)); app.get('load',loadjson); function *loadJson(){ var that = this; load(function(result){ that.body = result; }); }
但我得到这个错误:
_http_outgoing.js:331 throw new Error('Can\'t set headers after they are sent.'); ^ Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:331:11) at Object.module.exports.set (G:\NAP\node_modules\koa\lib\response.js:396:16) at Object.length (G:\NAP\node_modules\koa\lib\response.js:178:10) at Object.body (G:\NAP\node_modules\koa\lib\response.js:149:19) at Object.body (G:\NAP\node_modules\koa\node_modules\delegates\index.js:91:31) at G:\NAP\Server\OlapServer\index.js:40:19 at G:\NAP\Server\OlapServer\OLAPSchemaProvider.js:1599:9 at _LoadCubes.xmlaRequest.success (G:\NAP\Server\OlapServer\OLAPSchemaProvider.js:1107:13) at Object.Xmla._requestSuccess (G:\NAP\node_modules\xmla4js\src\Xmla.js:2113:50) at Object.ajaxOptions.complete (G:\NAP\node_modules\xmla4js\src\Xmla.js:2024:34)
为了澄清事情,让我们把你的callback写成
//Calback function function load(callback){ setTimeout(function() { var result = JSON.stringify({ 'my': 'json'}); callback(/* error: */ null, result); }, 500); }
在Koa世界中,这被称为thunk
,这意味着它是一个只有一个参数的asynchronous函数:与原型(err,res)的callback。 你可以查看https://github.com/visionmedia/node-thunkify获得更好的解释。
现在你必须写你的中间件
function *loadJson(){ this.type = 'application/json'; this.body = yield load; }
这主要是因为KOA是基于生成器的,如果你在中间件的顶部它不支持callback。 所以它不等待function完成。 最好的解决办法是把你的function转换成承诺。 诺言与KOA很好地合作。
我有一个非常类似的问题,使用braintree(常规callback)和koa。 根据你的代码,我需要做的唯一的改变是使用load函数,以及它是如何调用的。
router = require('koa-router'); app = koa(); app.use(router(app)); app.get('/load',loadjson); function *loadJson(){ this.body = yield load; } // Callback function function load(callback) { // Prepare some data with xmla4js and ajax whatever_inputs = {...}; final_method(whatever_inputs, callback); }
上面Jerome和Evan的解释是绝对正确的, thunkify看起来像是一个适合自动执行的过程。
虽然thunks是一个好主意,在我看来, Promise
是一个更好的长期方法。 许多库已经转向了对asynchronous的承诺,而不是旧的节点标准callback(err, data)
,而且它们很简单,可以包装任何asynchronous代码来实现承诺。 其他开发者将会有Promise的经验,并自然地理解你的代码,而大多数人将不得不查看什么是“thunk”。
例如在这里,我正在将尚未承诺的jsdom包装在一个承诺中,所以我可以把它放在我的koa生成器中。
const jsdom = require('node-jsdom'); const koa = require('koa'); const app = koa(); app.use(function *() { this.body = yield new Promise((resolve, reject) => jsdom.env({ url: `http://example.org${this.url}`, done(errors, { document }) { if (errors) reject(errors.message); resolve(`<html>${document.body.outerHTML}</html>`); }, })); }); app.listen(2112);
const jsdom = require('node-jsdom'); const koa = require('koa'); const app = koa(); app.use(function *() { this.body = yield new Promise((resolve, reject) => jsdom.env({ url: `http://example.org${this.url}`, done(errors, { document }) { if (errors) reject(errors.message); resolve(`<html>${document.body.outerHTML}</html>`); }, })); }); app.listen(2112);
const jsdom = require('node-jsdom'); const koa = require('koa'); const app = koa(); app.use(function *() { this.body = yield new Promise((resolve, reject) => jsdom.env({ url: `http://example.org${this.url}`, done(errors, { document }) { if (errors) reject(errors.message); resolve(`<html>${document.body.outerHTML}</html>`); }, })); }); app.listen(2112);
在语义上,承诺和生成器携手合作,真正澄清asynchronous代码。 发电机可以多次重新input,并产生多个值,而承诺意味着“我保证我稍后会为你提供一些数据”。 综合起来,你会得到关于Koa最有用的事情之一:产生承诺和同步值的能力。
编辑:这是你的原始示例包裹着一个Promise来返回:
const router = require('koa-router'); const { load } = require('some-other-lib'); const app = koa(); app.use(router(app)); app.get('load', loadjson); function* loadJson() { this.body = yield new Promise(resolve => { load(result => resolve(result)); }); }
要跳过Koa的内置响应处理,你可以明确地设置
this.respond = false
如果您想要写入原始的res
对象而不是让Koa为您处理响应,请使用此选项。
在调用callback之前,头文件已经通过内置的响应处理写入了。
- Mongoose在节点中的“model.findById”之后做一些事情
- asynchronoussocket.io JavaScriptcallback不工作
- 混合asynchronous操作(callback和承诺)完成后如何执行任务?
- 强制x客户端等待node.js中客户端y的callback的最佳实践
- 删除包装在匿名函数中的命名callback?
- Express Async – 发送后无法设置标题,双重callback?
- 在Javascript中通过variables作用域来维护variables
- 执行'n'asynchronouscallback后,node.js执行函数
- 我知道callback函数asynchronous运行,但为什么?