我发现很多会谈说Node.js因为回调地狱而糟糕,Go因为它的同步模型而很好。
我觉得Go也可以像Node.js一样回调,但是以同步的方式。我们可以pass anonymous function and do closure things
那么,他们为什么要在回调视角中比较Go和Node.js,好像Go不能成为回调地狱。
或者我误解了Go中回调和匿名函数的含义?
答案 0 :(得分:42)
很多事情需要时间,例如等待网络套接字,文件系统读取,系统调用等。因此,许多语言,或者更确切地说是他们的标准库,包括其功能的异步版本(通常除了同步版本),以便您的程序能够在平均时间内做其他事情。
在node.js中,事情更加极端。它们使用单线程事件循环,因此需要确保您的程序永远不会阻塞。它们有一个非常好的标准库,它是围绕异步的概念构建的,它们使用回调来在事情准备就绪时通知你。代码基本上如下所示:
doSomething1(arg1, arg2, function() {
doSomething2(arg1, arg2, function() {
doSomething3(function() {
// done
});
});
});
somethingElse();
doSomething1
可能需要很长时间才能执行(例如,因为它需要从网络中读取),但您的程序仍然可以同时执行somethingElse
。执行doSomething1
后,您需要致电doSomething2
和doSomething3
。
Go on另一方面基于goroutines和渠道的概念(google for" Communicating Sequential Processes",如果你想了解更多关于抽象概念的话)。 Goroutines非常便宜(你可以同时运行几千个),因此你可以在任何地方使用它们。 Go中的相同代码可能如下所示:
go func() {
doSomething1(arg1, arg2)
doSomething2(arg1, arg2)
doSomething3()
// done
}()
somethingElse()
尽管node.js专注于仅提供异步API,但Go通常鼓励您只编写同步API(没有回调或通道)。对doSomething1
的调用将阻止当前goroutine,doSomething2
将仅在doSomething1
完成后执行。但这在Go中不是问题,因为通常有其他可用的goroutine可以安排在系统线程上运行。在这种情况下,somethingElse
是另一个goroutine的一部分,可以在此期间执行,就像在node.js示例中一样。
我个人更喜欢Go代码,因为它更容易阅读和推理。 Go的另一个优点是它也适用于计算繁重的任务。如果你在node.js中开始一个不需要等待文件系统调用网络的大量计算,这个计算基本上会阻塞你的事件循环。另一方面,Go的调度程序将尽力在几个系统线程上调度goroutine,如果你的CPU支持,操作系统可以并行运行这些线程。
答案 1 :(得分:10)
我觉得Golang也可以像Node.js那样以同步的方式进行回调。因为我们可以传递匿名函数并做关闭事情
那么,为什么他们在回调视角比较Golang和Node.js,好像Golang不能成为回调地狱。
是的,当然也有可能在Go中搞砸了。您没有看到与node.js一样多的回调的原因是Go有通信渠道,这允许在不使用回调的情况下构建代码的方法。
因此,由于存在通道,因此不经常使用回调,因此不太可能在回调受感染的代码上发现错误。当然,这并不意味着你也不能用频道编写可怕的代码......