本人不搞node,朋友微信发的,无意引战
发布于 19 天前 作者 coordcn 3387 次浏览 来自 分享
63 回复

那好吧,那就不点击给你朋友引流加访问量了。

知道了知道了,V2上已经有人发过了

无意引战,还发出来。 心里没点B数吗🙄😒:)

Node.js之父在2012年就离开社区的,然而这5年发展的依然很好,并无影响。这篇文章本来没什么问题,但有些人借位营销就恶心了。

不是最好,也不是最差,是性价比比较高的,可惜node做后端一直不温不火,java,php利益相关,只有新项目用,微服务架构下,会更好一些。很多人node是用错的,不是用node就什么都用,分清场景。不误解,不传谣,合适自己的才是最好的

一个同时能弄好机器学习和web开发的人。。。学不来。。。

@i5ting 同意狼叔的观点。我想补充的是:

Ryan提及的“大型服务系统”是 《DNS服务器集群》类的 底层基础设施。这个领域一般都是Cpp的主场。类似于我单位里的LBS服务组件,Go都不一定是最佳匹配的工程技术,因为Go是GC语言 且 有垃圾回收延时 — 因此,我不认为Go或JAVA比较js高级多少,他们无非是50步笑100步。此外,如果不考虑Cpp的开发者比较多、容易招聘的话,我认为Rust才是 最佳 与 最折中的 工程技术选择(内存安全 与 开发效率,还不需要那么多的老司机)。

所以,我认为Ryan的观点 与 Node.js在后端“胶水语言”的使用场景并不冲突。即,这两者就不在同一个维度上:

  1. Ryan说的是 被“胶水语言”包装的核心引擎。难道JAVA与PHP就适合做这一部分的业务了?
  2. Node.js是包裹核心的“胶水”。除了与html5技术不兼容之外(潜在增加了人力成本与学习成本),JAVA与PHP相对于Node.js又有什么独一无二的技术优势?

@stuartZhang 希望大牛们多出来答疑。像这种意味模糊的文章。我等初级人员容易被误导。

@i5ting

赞同你的观点,我之所以没有把文章的标题也复制过来,就是不想引起骂战,而是希望读过文章之后引起有心人的思考。

合适的场景用合适的技术这个技术选型的根本点很重要,后端真的不是哪一门语言能一统天下的。

有些人对我转这样的文章有意见,甚至有的人恶语相加。你们可以这么想,我不发,别人就不会发?我不发,别人在其他地方就看不到?那个引战的标题我特意没有转过来,这个标题是翻译的人后加的。

对这篇文章反应越大的,越激动的,可能是承受能力越不行的。对真正技术好的,不管是做node的还是不做node的朋友,一篇文章仅仅是一个看问题的角度而已。而且Ryan已经离开node的,他就是个了解内情的局外人。他说的对,听一听,不对的,他一句话能灭了node?况且人家的观点和现实情况是吻合的,node主战场还是前端工具链和初创项目,node也的确不适合做底层,node的编程模型相对于其他语言的确落后了,性能也不再有优势。

真正了解node的人,必然是对node优缺点都了如指掌的人,也是能够客观看待并接受node优缺点的人。

这个道理就如你喜欢某个女神,当你没有跟她深入接触的时候,你觉得这个女神是完美的,但当你跟她深入接触后会发现,女神也有缺点,也要吃饭拉屎,如果你发现了这些缺点并包容了这些缺点,你才真正准备好和女神结婚了,否则就有可能像李敖因为胡因梦便秘而和她离婚。

@renshunli

不是大牛,但可以给你点建议。

如果你有志于前端,node必学,因为现在前端的构建工具链基本都是node的搞的。

如果你有志于后端,则不仅仅要学node,其他框架,语言,数据库等都要学。

如果你想做一个项目原型,你对node比较熟悉,前后端都会,node是性价比比较高的选择。

@coordcn 淡定,哈哈,习惯就好了

我觉得 node 挺好的,适合初创公司,前后端一个语言,多爽,虽然 PY、Php 我都会,但是做 Web 还是觉得用 node 好,毕竟写多了 node,javascript 的功底也橙橙撑的往上长。 再说了大型应用,你见过哪个大型应用是一个人,或者一门语言完成的。简直就是扯虎皮拉大旗。

而且一个真正的高级后端开发工程师需要的知识量也挺多的,一点不比前端知道点少,以前我以为后端只是学个 linux ,搭建几个集群,开个框架架构就行了,其实并不然。要不然为啥出现那么多的 devops、dba 等其他职业,每一门语言所适合的领域都不一样。

我就用nodejs来做相对大型的应用, 用不了的人是人不行

@i5ting 必须有人给予信心指引。

最近常看到黑NodeJS都是說 結構混亂、天生single thread不好做mutli thread、速度不如靜態強型別語言(一定拿Go當比較)、沒有好的測試等; 我看留言的大大主要都是以應用場景(IO密集或CPU密集)來切分不同工具的採用(NodeJS vs Go),但因為我目前也是主力寫NodeJS,沒有其他動態語言如php/ruby/python等常用後端開發的動態語言,不知道有沒有大大可以比較一下NodeJS 與其他動態語言採納的場景?

还是那句老话,不考虑实际业务都是胡说八道

@renshunli 在我看来,计算机语言主要就分“GC语言”与“非GC语言”。在同为GC类语言的前提下,各种技术虽然各有偏重,但是,并不存在数量级的差距。

从历史上看,非GC语言一直都很清爽。主要也就包括这么几个计算机语言:C, Cpp 与 新秀的Rust。

但是,另一方面,非GC语言 又分为

  1. 虚拟机预安装语言(比如,JAVA需要JVM, JavaScript需要浏览器或Node.js)
  2. 虚拟机与App程序共同打包在一起的语言。最典型的就是Go。Go不需要预安装虚拟机。但是,你是否曾经怀疑过:Go没有预装的虚拟机,那么谁给它做内存管理?答案是:Go的虚拟机与App程序打包在一起了。但是,Go的虚拟机很小(相对于JVM而言),而且Go只做Server端的程序,程序安装包的尺寸并不是主要的 性能考量指标。所以,这个问题并不致命。

所以你是搞php的吧o(╯□╰)o

@coordcn

node的编程模型相对于其他语言的确落后了

这点能否展开来说说,我只看到文章里说 goroutine 好,但又自己说 JS 也有 async 函数。希望能说说 node 落后在哪里,其它语言哪些地方值得学习。

@ianchn 要想知道问题的答案,最好的方式就是自己去求解,别人的只能作为参考。

以下是我个人的理解:

从最初的callback,promise,generator/yeild,一直到async/await,异步程序编写方式越来越向同步靠拢。所以我评判语言异步模型先进与否主要是看和同步代码的相似度,最好的异步是没有一异步。所以async/await相对于完全同步的代码模型上肯定是落后了。但我并不赞同go的模型更先进的说法

回调的问题大家现在已经形成共识了,这个基于回调的异步模型,代码编写还是小事,后期维护那才是大事。基于回调的异步不是什么新鲜的东西,C语言通过函数指针实现,nodejs的异步库libuv就是用C语言实现的,有兴趣的大家可以去阅读相关源代码。

很多人对回调有一个误解,认为回调就是异步,其实回调只是异步的一种实现方式,回调是来保证同步的,保证我们业务代码的逻辑顺序的。 如果你不需要保证逻辑顺序,比如你开一个线程写入文件,你并不需要知道写入成功与否,你是不需要注册一个回调函数去接受这个线程的执行结果的。

这个就引出了一个问题,回调异步这种形式异步恰恰是为了保证同步,这就是编程模型和业务逻辑之间的冲突,ES这些年为了解决这个问题,引入了promise,引入了生成器,引人了async,其根本原因就是想解放程序员,我们必须承认,这些模型的引入相对于js这门语言而言是有进步意义的。但如果跟其他语言相比较,js已经落后了,当别的语言已经做到用同步代码写异步程序的时候,js还在醉心于async/await这种显式的异步语法糖,而且大家都认为这是一种理所当然的状态,那就有很大的问题了。

解决这个问题的钥匙在协程,erlang,lua,go,php(非官方)等语言都实现了stackful的协程,协程相对于线程而言,切换消耗小,可以将显式的异步代码转换为形式同步,实质异步的代码,也就是用同步模式写异步程序。我的主语言是C和lua,go略懂,我们以lua为例:

local fs = require("fs")
local ret, data = fs.readFile("text.txt")
print(ret, data)

这是我个人项目luaio里的一个例子,代码没有异步的影子,但read却是异步执行的,奥妙就是在协程,这段代码其实是被一个协程包裹着,当发起异步调用时,开启线程读文件,在C语言层面,我们主动让出当前协程的执行权,当读取线程完成后,把结果压入协程堆栈,唤醒协程继续执行。通过语言赋予的机制,我们很好的隐藏的异步实现。这种隐藏付出的代价就是协程切换的代价,跟回调比肯定是有损耗,但跟生成器之类的模拟协程比并不差,而且隐藏的更彻底。哪一种更先进大家肯定自己有自己判断。

协程模式也能实现并发或并行,不管是lua还是go都是开启多个协程,多个协程之间是并发或并行执行的,协程内部则是顺序执行,保证业务逻辑的。具体代码就不贴了,大家有兴趣的可以自行研究。

下面是js版本:

var fs = require("fs")

function readFile(name) {
    return new Promise((resolve, reject) => {
        fs.readFile(name, "utf-8", (err, data) => {
            if (err) {
                reject(err)
            } else {
                resolve(data)
            }
        })
    })
}

async function read() {
    var data = await readFile("t.txt")
    return data
}

read().then(v => console.log(v))

promise化的代码我手写的,大家正常都用包装函数,所以手写那部分代码可以忽略。我们主要关注,在这个过程中,async/await传递是什么?传递的是promise,跟lua代码比起来,这里不但出现了显式的异步关键词,更要命的是,这里异步传递的不是值本身,而是值的包装,我们要获得里面的值,还是需要用回调来拿,也就是说,async/await只能保证一定范围的同步,而且这种同步是基于promise的,值的传递依赖于promise。当然很多朋友已经适应了这种模式,毕竟他们从callback,promise,generator/yeild一路过来的,这些都不是事,但对其他人未必是这样。如果我直接写同步代码,又获得了异步执行的好处,我为什么不写纯粹的同步代码呢?借助协程,根本不需要任何包装,也不需要任何适应,甚至脑子里不需要有异步的概念,我就写出了异步程序。

@coordcn 求推荐性能很棒且有生产力的系统语言~

@coordcn 分析的头头是道啊

@renshunli node之父的意思是:除了所谓的,你根本不会接触到的大型项目,其他的用nodejs都是很好的。

@YUFENGWANG

选择语言看你自己的需求,还有就是自己喜欢,用着顺手舒服。

生产力这个东西因人而异的,跟语言的生态,自己对语言的熟悉程度,自己填坑的能力都是相关的。

按照应用层次不同我列出几个作为参考

  1. C,rust
  2. go,java,erlang
  3. javascript,php,python,lua

系统级C语言肯定是当之无愧的王者,但现在竞争者rust,go都是虎视眈眈的,完全取代不现实,但部分替代已经做到了。C语言语法简单,代码编写一定源码阅读量之后也不难,C语言难的是调试,一个段错误重现,捕捉,定位耗费十天半个月太正常了。我个人的选择是C语言。

应用级或者中间件,我个人认为java,go,erlang都是不错的选择,rust也可以考虑。我个人的选择是go。

接口级nodejs,python,php,lua都可以,他们都有相应的高性能实现版本,php的swoole,lua的openresty。我个人的选择是lua。

@coordcn 感谢详尽的分享。去看了一些资料,了解到 lua 实现了所谓 stackful、first-class 的 coroutine,这个确实是 JS 没有的。

@coordcn 我最近一年都在从事 私有数据格式的、矢量地图的、即时渲染项目。根据我的项目经验,我认为

await关键字显示地标记出《形式同步代码中的“异步停顿”》对于维持代码逻辑的清晰很有帮助。

_

我举一个我经常会处理的一类问题为例:

  1. 地图的渲染(无论是Canvas 2D或WebGL)都可以被概括为: 第一,捕获用户行为(例如 zoom in/out)。 第二,异步地获取数据(Fetch API或读IndexedDB缓存) 。 第三,同步地修改 GL Context状态,完成绘制。
  2. 因为第二步是异步,所以当用户连续地操作时,第一步的用户行为判定就有可能过期。例如, 首先,用户zoom in到15。 然后,程序开始异步读取IndexedDB的二级缓存(可能需要400毫秒)。 接着,用户接着zoom in到16。 此时,IndexedDB的读取操作完成。正在这个程序位置就需要插入一个“之前的用户行为(zoom in到15)判定是否过期”条件判断。
  3. 若没有await关键字,这个程序类似于
map.onZoomChange = function(event){
  const zoom = event.newZoom;
  cont vectorData = readIndexedDB(zoom); // 这是异步操作。
  // 异步操作之后检查:地图的zoom level是否再次发生了变化。如果异步操作之后的zoom level已经变化了,那么IndexedDB的读取值应该立即作废。
  if (map.getView().getZoom() === zoom){ // 因为没有显示地标记readIndexedDB(zoom);是异步操作,所以这个if块显得很突兀。**若以后换人维护这段代码,很有可能因为不理解readIndexedDB(zoom)是异步的,而直接地删除这个看似多余的if判断。**
    drawMap();
  }
};
  1. 若有await关键字,那么这个代码就清晰多了。
map.onZoomChange = async function(event){
  const zoom = event.newZoom;
  cont vectorData = await readIndexedDB(zoom); 
  if (map.getView().getZoom() === zoom){ // 所有有Await关键字的程序位置都应该配有一个“用户行为判定是否过期的”条件判断。后继的代码维护者能够根据一条很简单的规则,查阅代码与改bug。
    drawMap();
  }
};

综上所述,我认为async/await关键字显示地标记出 “形式同步代码中的 异步操作语句”是有帮助与周到的,甚至是先进的。

很多天之前看过采访的英文原文,我也喜欢go,哈哈 @coordcn

@stuartZhang

用async/await关键词隐式注释业务逻辑这个做法本身就值得讨论,我个人认为直接在业务逻辑代码旁边写明为什么这么做比两个关键词要让人容易理解得多。你可以做个试验,让别人来理解你的代码,是不带关键词但有注释容易理解,还是带关键词不带注释容易理解。用这个来说明先进性恐怕说服力很不到位。

async/await只能保证函数内部的形式同步,函数执行后取值还是需要通过then来取得,这跟完全形式同步比,说是更先进恐怕也不合适,真正的形式同步任何时候返回的都是自己想要的值,根本不需要去关注promise,promise从某种意义上来说是传递的媒介,所有异步操作都必须被包装成promise才能运作,最后也必须通过promise取的最终的值,真正的形式同步是不应该有这种负担的。

对于从callback,promise,generator/yield一路过来的人,这些都不是问题,async/await的确是巨大的进步,但跟其他语言相比,离形式同步看起来也不差很多了,但实际上还差很远。如果要引入真正的stakful的协程,前端体系要推倒重来,而javascript不可能为了nodejs来改变,node只有被动的接受,被javascirpt标准推着走。

我说node的缺点,不代表我鼓吹其他语言,反对node。我认为node作为前端构建工具链,为前端工程化作出了巨大的贡献,我认为能够hold住前后端的同学,尤其有深厚前端功底的,选择node是正确的,选择跟你的项目大小无关,跟你的能力有关。

有的人还认为node是编程模型最先进的,生态最好的,甚至还认为性能也是最好的,那我有责任出来说一些实话,会让一些人不舒服,但后端真不是一门语言能够扛得起来的,选择node,有志于后端的,必须要关注其他后端语言。

@coordcn 我的选择是

  1. 非GC类语言。我选择Rust,原因是WASM与高性能后端服务组件。(打点,要求性能)
  2. GC类语言。我选择ECMAScript,原因是广泛的跨平台适应性。(打面,要求跨平台成本低)

最终是:点面结合。GC类语言真心是太多了。但是,我精力有限,所以选择一款平台适应性比较强的GC语言。

@stuartZhang 这种情况可以约定把函数名写成 readIndexedDBAsync ,同样也能实现

显示地标记出 “形式同步代码中的 异步操作语句”

@stuartZhang

的确,语言选型要结合自己的实际需求。

@coordcn 同意:通过写明确的注释来解释关键部分的业务逻辑 是 最安全的作法。

另一方面,语法层面的await关键字标记,让我更放心和更踏实,因为注释是非语法强制的且有懒惰风险;await关键字是语法强制的且提供最低的可读性保障。

@stuartZhang

如果不需要promise作为媒介,多写几个关键字提高可理解性是可以的,@ianchn 的方案也是可以的。

@coordcn 支持,看看社区都在玩啥就知道node的定为是后端还是前端构造工具,。

@imhered 这个老哥一直致力于毁灭cnode的浮躁之风

重点都在讨论promise async 对我来说都不重要…也不在乎。 看到 stuartZhang讲的 广泛的跨平台适应性。(打面,要求跨平台成本低) 这点还是比较关心的内容。 现在市面语言多了。哪有时间去研究哪个比哪个好多少,又坏多少。只关心有没有前途与钱途……

@renshunli 我现在最大感触就是 需要学的内容太多了。但是,我又学得慢。虽然html5是我的主业, 但是我之前一直私下里学习Rust。但是,后来因为工作原因又不得不天天看GLSL。

@renshunli 我个人认为,类似于JAVA的GC语言,今后在大型科技企业内的前途 并不如ECMAScript和Rust好。

  1. 以点破面。JAVA的性能远不及Cpp与Rust。
  2. 以面盖全。JVM在各种终端上的普及度根本就没有办法与各类浏览器比。

所以,这样的GC语言很是“高不成低不就”。表面上看,JAVA类GC语言很是“万金油”(什么都能)。但是,它无论在哪个主战场上都做不到极致(即,什么都做不到最好)。

除非是苹果(拥有自己的独立且盈利的硬件平台),但是,如果作为一个软件运营商,创业之初,选择JAVA类GC语言能够降低技术成本。但是,一旦打开了市场突破口,有了盈利产品,多半会考虑 向 技术特点更加 鲜明的技术转型。

@renshunli 还有,你同意我的观点。给我点个赞,好不?

@stuartZhang 最近翻了翻知乎。上面聊这个话题聊的挺火热。也找到了一些有用的信息。内容还是比较健康的。

@coordcn 感觉国内c++, java, js还是主流

@YUFENGWANG

选择语言跟你的需求相关,跟自己对语言的熟悉程度相关,跟自己的填坑能力相关。

C++是主流,培养一个能填坑的程序员要花多长时间?这门语言恐怕是从入门到放弃人数最多的语言。

java是主流,但对我而言,go上手更快。

javascript在前端是绝对的主流,但后端可选择的语言太多了,javascript在后端也是主流么?

其实选语言是很个人的问题,语言的优劣深入使用后才知道。 我对C,go,lua都不满意,很多坑得自己填上。lua后端缺这库,缺那库,没关系,只要C语言有的,lua就有了。实在不行,看看其他语言有没有解决方案,rpc,http丢给其他语言。

lua国内不主流吧,go还可以,近几年势头很好

@coordcn 黑体字对promise说的真到位,async也不能改变这种负担。还有很认同这么多年了node都没有扛起后端,哎。

@i5ting 微服务下node做后端真的好吗?有工程化开发的文章吗?

@stuartZhang await 是显示的,但是受不了promise封装。

@YUFENGWANG

lua搞web肯定不是主流,用openresty做API网关是不错的选择,有nginx基础上手很容易。

@m3shine

node在后端肯定是有一席之地的,现在node本身和社区都成熟了,刚火的时候秒这语言那框架的,现在用的顺手的默默的用,不想用的肯定也不会用。

后端语言性能现在差距不大,拼的就是生态,编程模型,上手难度,开发效率。

node最大的贡献在前端工程化,这个怎么赞美都不为过。但后端要node来扛肯定不现实,毕竟竞争语言太多了。而且前端自己也竞争做后端的人才,很多公司招聘也都偏向于前端。

我认为,有志于前端必学node,有志于后端node是可选的。如果选node后端的话,必须要有一定的前端基础。

node就是前后端的桥梁,可以偏向某一端,但知识体系必须联系起来才能创造价值。

@coordcn @i5ting 同意“很多公司招聘也都偏向于前端”。我认为:

  1. 后端的(商业)业务很容易形成“赢者通吃”的寡头垄断。试问:全国能有几十家企业有机会做 像 阿里 与 腾讯 那样的 “大数据分析”,而且,还能 时不时地 发布一些颇有社会价值的 大数据分析结果?
  2. 如果因为寡头垄断造成这类公司很少的话,自然地 偏重后端的 就业市场的 规模 就会很有限。
  3. 另外,几乎我所知道的公司 都 重点研发 各种设备上的“大数据报表”。其中,甚至还有一些公司打着“大数据分析”的幌子,其实招的“大数据报表”的人才。
  4. 不同于“大数据分析”运行在后端专用业务服务器的Hadoop程序上,大报表主要是,通过Rest API获取大数据分析结果(可能会有少量的二次加工)。然后,技术重点就是Canvas 2D,WebGL(例如,好像有一款《3D机房管理》的产品),和移动平台适配了。

@coordcn node就是给前端玩的。又逼回spring cloud生态了。

@m3shine 的确,node适合前端相关的人玩,其他后端如果要转前端也可以考虑,node纯做后端一点优势也没有。

@m3shine 我感觉Promise的实用度最高。最近刚刚遇到了一个坑《鉴于“Chrome 60+的Performance工具”,我被async/await给坑了》。我甚至有些后悔大面积地使用async/await了。

看不下去了。讨论的最后结果就是玩具吗?真是醉了。像这种没营养的帖子还是少发吧。有意思么?觉得哪个语言好就去哪个社区论坛混好了。天天跑这来瞎扯啥。

@renshunli 不是没营养,正是因为事关前途。你不觉得这么多年了还在讨论这个问题,本身就是一个值得思考的现象吗?无论从市场、企业、从业人员,node在后端的重量在哪里?

@m3shine 后端技术市场的《碎片化》已经不可逆转了。在可预知的将来,应该会出现更多的计算机语言参与到这个(狭窄)领域的 激烈竞争中来。之前的新参与者有Swift, Kotlin与ECMAScript,还有Rust。后面还会有哪些语言会出现,谁又知道呢?在后端领域,开发者的选择只能会越来越多,越来越丰富,因为《碎片化》不可逆。

至于,Node.js在后端业务中的立足点,在不考虑WASM支持的条件下,是做“胶水语言”。类似于,Ruby, Python, PHP,等等。

  1. 对数据库读写与查询:索引管理在DB里,不在JS程序里。
  2. 基于Redis做一些会话管理:Session ID的匹配与筛选,在纯C的Redis里。
  3. 调用FFmeg做一些视频与音频的转码。

至于“这些年,Node.js在后端应用场景的讨论”,或许是 开发者对Node.js期望比较高,还想让她担当除了“胶水”之外的角色。而,这类角色因为计算密度太高,一般都不适合于GC类语言来完成(不只是JS)。但是,因为WASM的支持,可能以后Node.js也能够覆盖这些领域吧。

@stuartZhang 有你这番话足矣

@m3shine 那请你给我点个赞好吗?

@stuartZhang 赞了,这么多可爱的人

回到顶部