回调地狱问题并不是通过隐藏复杂性才得以解决的。相反,是语言和范式的演变解决了这个问题。通过使用async函数,我们的代码变得更加美观。
通过明确定义的类型和接口提升清晰度当我还是Java的死忠时,我坚信严格的类型检查对开发大型的应用程序来说是有百利而无一害的。那个时候,微服务的概念还没有出现,也没有Docker,人们开发的都是单体应用。因为Java具有严格的类型检查,所以Java编译器可以帮你避免很多错误——也就是说可以防止你编译错误的代码。
相比之下,JavaScript的类型是松散。程序员不确定他们收到的对象是什么类型,那么程序员怎么知道该怎么处理这个对象?
但是,Java的严格类型检查同样导致了大量样板代码。程序员经常需要进行类型转换,或以其他方式确保一切都准确无误。程序员需要花很时间确保类型是准确的,所以使用更多的样板代码,希望通过及早捕获和修复错误来节省时间。
程序员不得不使用复杂的大型IDE,仅仅使用简单的编辑器是不行的。IDE为Java程序员提供了一些下拉列表,用于显示类的可用字段、描述方法的参数,帮助他们构建新的类和进行重构。
然后,你还得使用Maven……
在JavaScript中,不需要声明变量的类型,所以通常不需要进行类型转换。因此,代码更易于阅读,但可能会出现未编译错误。
这一点会让你更喜欢Java还是痛恨Java,取决于你自己。十年前,我认为Java的类型系统值得我们花费额外的时间,因为这样可以获得更多的确定性。但在今天,我认为代价太大了,使用JavaScript会要简单得多。
使用易于测试的小模块来扫除bugNode.js鼓励程序员将程序划分为小单元,也就是模块。模块虽小,却能从一定程度上解决刚刚提到的问题。
一个模块应该具备以下特点:
自包含——将相关代码打包到一个单元中;
强壮的边界——模块内部的代码可以防止外部代码入侵;
显式导出——默认情况下,代码和模块中的数据不会导出,只将选定的函数和数据暴露给外部;
显式导入——声明它们依赖哪些模块;
可能是独立的——可以将模块公开发布到npm存储库或其他私有存储库,方便在应用程序之间共享;
易于理解——更少的代码意味着更容易理解模块的用途;
易于测试——小模块可以轻松进行单元测试。
所有这些特点组合在一起,让Node.js模块更容易测试,并具有明确定义的范围。
人们对JavaScript的恐惧源自它缺乏严格的类型检查,所以可能很容易导致错误。但在具有清晰边界的模块中,受影响代码被限于模块内部。所以,大多数问题被安全地隐藏在模块的边界内。
松散类型问题的另一个解决方案是进行更多的测试。
你必须将节省下来的一部分时间(因为编写JavaScript代码更容易)用在测试上。你的测试用例必须捕获编译器可能捕获的错误。
对于那些想要在JavaScript中使用静态检查类型的人,可以考虑使用TypeScript。我没有使用TypeScript,但听说它很不错。它与JavaScript兼容,同时提供了有用的类型检查和其他特性。
但我们的重点是Node.js和JavaScript。
包管理一想起Maven我就头大。据说一个人要么爱它,要么鄙视它,没有第三种选择。
问题是,Java生态系统中并没有一个核心的包管理系统。Maven和Gradle其实也很不错,但它们并不像Node.js的包管理系统那样有用、可用和强大。
在Node.js世界中,有两个优秀的包管理系统,首先是npm和npm存储库。
有了npm,我们就相当于有了一个很好的模式用来描述包依赖性。依赖关系可以是严格的(指定具体的版本),或者使用通配符表示最新版本。Node.js社区已经向npm存储库发布了数十万个包。
不仅仅是Node.js工程师,前端工程师也可以使用npm存储库。以前他们使用Bower,现在Bower已被弃用,他们现在可以在npm存储库中找到所有可用的前端JavaScript库。很多前端框架,如Vue.js CLI和Webpack,都是基于Node.js开发的。
Node.js的另一个包管理系统是yarn,它也是从npm存储库中拉取包,并使用与npm相同的配置文件。yarn的主要优点运行得更快。
性能曾几何时,Java和JavaScript都因为运行速度慢而横遭指责。
它们都需要通过编译器将源代码转换为由虚拟机执行的字节码。虚拟机通常会进一步将字节码编译为本地代码,并使用各种优化技术。