我在bearcat查询语句的callback中执行跳转,为什么会报cant set headers after they are sent 这个应该这么解决啊 我路由那些都是用的koa 数据库因为要用sql-mapping 就直接用了bearcat-dao,不知道是不是因为koa的原因呢
这次请求已经完成了,也就是说你之前某个地方调用了res.end()。 这多半是万恶的回调造成的逻辑不清的后果,还好node考虑的周到。
看下res.end()都在什么地方被调用了。 查一下有没有并行回调之类的,问题多半出在那里。
@wenshiqi0 的确是koa调用的,koa在你之前调用了res.end()
还是因为你的回调执行顺序造成的,koa的res.end()在你回调执行之前就调用了。
http://www.infoq.com/cn/articles/generator-and-asynchronous-programming/田永强的文章,读完就明白了。
不过这种半调子的协程其实增加了编码和理解的难度,需要捋一捋的,这东西会用(随便找个转换库,转换一下,放到yield后面,yield返回值就是回调的返回值),不代表就真的理解了。javascript协程设计还是挺别扭的,特别是要兼容回调的时候,要整个弄明白了要花点时间的,我个人更喜欢lua提供的协程概念,清晰,简单,不复杂。我现在已经实现了形式同步下的异步,正在思考如何完善并发,这方面工作,fibjs做了一点,但是还是有问题,openresty根本没有碰并发,当然lua也可以通过开新的协程来实现并发,但这种新开协程的做法是有代价的,我更倾向于每个客户连接一个协程,在这个协程上做所有异步调度。
javascript有越来越向杂糅怪胎发展的趋势,基本是为了解决一个复杂的问题,引入了另一个复杂的问题,心很大,但力不济。
@wenshiqi0 问题处理了么?田永强的文章你要仔细看,你要用koa,就必须要自己会转换。
我给一个lua回调转协程的例子给你,你就会明白javascript的半调子协程有多坑爹。很多人是没见过好的,就觉得generator老牛逼了。
fs.readFile('test.txt', 'utf-8', function(err, data)
print(data)
end)
接下转换函数
function wrap(func)
local current
return function(...)
local args = {...}
args[#args + 1] = function(...)
local cur = current
current = nil
coroutine.resume(cur, ...)
end
fs.readFile(unpack(args))
current = coroutine.running()
coroutine.yield()
end
end
使用
local readFile = wrap(fs.readFile)
local co = coroutine.create(function()
local err, data = readFile('test.txt', 'utf-8')
console.log(data)
end)
coroutine.resume(co)
javascript的协程有这么清晰么?没有。。。
@coordcn 我用thunkify加co可以正常的转化callback到generator 但是我用的那个查数据库的函数用的是bearcat 封装了几层 其实就是把原来的函数直接return了过来 这种怎么转化呢
先去掉包装做,想明白了,随便怎么包都一样,关键你取数据的回调在哪里?我个人比较反对javascript搞面向对象,面向对象只在的确需要有继承关系的地方使用,乱用得不偿失。为了面向对象而面向对象的一定是垃圾代码,需要面向对象的地方,c也能面向对象,不需要的地方,除了让代码变长,没有半点好处。
function yourFunOld(name, callback){
db.get(name, function(err, data){
if(err) return callback(err);
callback(err, data);
});
}
你找到回调调用那个地方,两种方案,一种什么都不变,直接对函数thunk。
另一种其他都不变,去掉callback参数,返回一个包裹回调的函数。
function yourfun(name){
return function(fn){
db.get(name, function(err, data){
if(err) return fn(err);
fn(err, data);
});
};
}
这两种方案,都能使generator.next()返回值{value:, done:} 中的value是一个函数,这个函数就是上面return返回的那个。
var data = yield youfun('name');
var ret = generator.next();
ret.value(function(err, data){
if(err) throw err;
generator.next(data);//到这里就传递给了data
});
你们公司就你一个人用node?没人交流么?
继续吐槽es6的设计,能做这样标准出来的都是神人,自己牛逼了不写程序,专门想法子折磨程序员。
我的异步目标是形式同步。 local data, err = db.get(‘name’) 世界多美好,一句话就解决了所有问题,这是货真价实异步的。
@coordcn 我这个小小的实习生就是被抓进去做这个的 公司基本没人用nodejs 他们老一辈不想学这些了 我就去现学现做 我准备明天用promise做 那个包装也不是oo的 只是上头要求这样 不要暴露dao和sql语句 所以需要包装一层
@wenshiqi0 promise一样能行,没人交流最痛苦了,但只要努力,进步很快的。
他们不学是正确的,很多公司用node,其实都是贪小便宜,性能,前后端通吃,其实都是骗人的,性能node也就那样,两三年前还能吹吹牛逼,现在大家都在一个水平上,比node好的也不少。前后端通吃更是扯蛋,前后端的复杂度不是一个级别的,用前端的写点简单的项目还凑合,稍微复杂点的,靠谱点的都不敢用node。node的这个东西,刚上手给人感觉很好,但用着用着就感觉不对了。
@wenshiqi0 你指的是我说的形式同步? 这个不是并行,node严格来说,不存在并行,线程可以算,但前提是分别在不同CPU核心上运行,才算并行。 node所谓并行,其实是并发,命令发出去了,执行还是一个个顺序执行的。node的优势仅仅是发了命令不需要傻等命令执行完毕,在返回之前可以发布其他命令。
形式同步代码跟实质同步代码是一样的,在c层面做了协程调度工作,看起来像同步,实质是异步的。
c层面还是要用回调的,只是做了回调转换罢了。
我已经实现了这个部分工作,tcp模块已经完成,还缺一个connect,争取这个月底前完成,下个月开始做http模块和websocket模块,做完我会写一个聊天程序和游戏程序做示范,然后发布,招募志同道合的一起完善。
@wenshiqi0 c也是我最喜欢的,很干净,整洁,又足够灵活。lua我也很喜欢,和c结合很紧密,用起来很爽。
javascript也不错,但对es6我很不满意,加了很多莫名其妙的东西,可能我老了,不喜欢折腾了,越来越倾向于c那种很稳定的东西。
@wenshiqi0 代码在我github上,links,现在还很原始,只相当于实现了node的os,process,cluster,net,dns模块。原理很简单,tcp模块看完就知道怎么利用协程将回调转换为形式同步了。这个东西要能用,还要实现,http,websocket,redis,mongodb,mysql,https,tls。还有测试,demo,文档。
我是需求驱动加测试驱动的,不完全是,设计的目标就是能够很方便的实现聊天,游戏服务器。今天做了个聊天服务器的试验,客户端用node写的,服务端用links,发现了一个内存问题,也发现了协程调度问题,当客户端速度很快的发消息的时候,协程调度一开始是比较平均的,但是慢慢就会集中到某个协程上去,最后其他协程就不活跃,就这个协程在发送接收了。这个问题在加大客户端发送间隔后消失,但这个问题如果不解决的话,就有可能造成拒绝服务攻击。
@wenshiqi0 昨天的协程切换调度问题看来是跟内存错误是一起的,内存错误解决了,调度就正常了。在valgrind里执行可能效率也会降低不少,所以出现了协程的切换调度问题。我看人家的测试,说lua的协程切换是每秒600万次,luajit可以做到2000万次,在切换上应该没问题。
@coordcn 情况有点不一样 实际上上面两层方法里面只有一个return语句 直接把旧函数renturn了 而这个旧函数是bearcat通过id在查找到的 而这个返回的函数中有一个参数为cb 就是callback 我用co里面的promise的处理方法来一直报错说cb不是一个function
@coordcn 其实也没有什么值得分享的 还是我对异步和异步流程的不熟悉 koa这趟框架背后全部用generrator封装了 全部的异步流程也是用这个来控制的 今天在debugger的时候突然发现了koa源代码外面有一个很大的co(),也就是所有的中间件都被放在了co下面 基本上我们所要处理的异步代码就完全表现的是同步的形式 只是node很多框架还是用的cb的形式 我最后是选择了bluebird的fromnode来将回调转换为promise 我觉得这个bluebird非常不错 我看源代码 基本上对大多数的promise实现都能支持 而且网上说速度也是最快的 使用相当简单 这样就完全去回调了 tj的doc虽然把我看得云里雾里的 但是明白之后确实感叹非常好用 虽然看到之前有人说这种实现太浮夸了 但目前而言我觉得koa吧回调处理的非常好 晚点我想自己实现一个简单的fromnode 不过用还是就用bluebird了
@wenshiqi0 这就是node最大的软肋,不管是callback,还是generator都会让人搞得云里雾里,也就是对程序员不是那么友好(尤其在错误处理和调试上)。世界上有几个像TJ那样的神人呢?我坚持认为好的工具必须是大众化的,简单的,容易被一般人理解的,而不是被个别精英垄断的。你碰到的问题如果有更好异步模型,异步操作能够在同步代码下实现,会简单得多。
node的创立者当初那么反对协程,认为回调才能保证更纯粹的异步模式,可是现在大家都用脚在投票,javascirpt越来越协程化,不管是promise还是generator,都在努力的实现用伪同步来实现(虽然很困难,很别扭),技术必须服务于大众,而不是少数精英的玩具。
形式同步一定会实现,到那个时候,程序员才真正获得了解放。技术也必然朝这个方向发展,通俗来讲,因为人类总是想偷懒,哪怕是一秒钟的思考。用政治经济学来讲就是减少了必要劳动时间,提高了生产力,单位时间内程序员能够创造出更多产品。