一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
大致概念咱先统一一下
如果以工作内容对前端进行分类,那我们大概知道,前端,写界面的。
后端,提供数据的。
前端和后端的交互,就用登录来举个例子吧。
用户输入 -> 前端拿到输入数据发给后端 -> 后端接收 -> 后端拿到数据 -> 数据表操作,判断用户存在不存在 -> 如果存在,给前端返回一个结果 -> 前端拿到结果,展示对应的信息或者跳转界面
大概就是这么一个流程。那我们可以发现,前端的主要工作是页面和后端返回数据的处理,后端则是进行接收数据和数据表处理。
前端主要的开发语言是 JS ,后端开发的语言就多了,什么 PHP,Go, Java 等等。NodeJS 应该也算是一种。
那你有没有想过,为什么前端就这么一个语言,而后端有那么多种语言?为什么前端的语言不能操作数据库而后端的语言可以?NodeJS 和 JS 之间到底有什么不可告人的关系?
首先,我们先了解下这个。
代码究竟是怎么在计算机跑起来的?
这个深入理解较复杂,我暂时设定几条既定规则。
我们现在接触到的 JS、Java 等都属于高级语言,能够提高我们的开发效率,但计算机无法直接执行。
高级语言需要转化为机器语言才能被计算机执行。
明确了以上内容,我们可以这么理解,无论是前端还是后端的代码,它都需要一个中间工具进行转换,转换成机器语言后,完成相关的运算,比如基础的加减乘除。
你说,那不对啊?我 js 写完,就直接用浏览器打开了啊?
那有没有一种可能性,浏览器中有一个转换的中间工具呢?那就是 V8 引擎。(V8是一个由Google公司开发的开源JavaScript引擎,使用C++编写)
而想要运行 NodeJS ,我们得下载 node 模块搭建 node 运行的环境。我们可以大致理解为,下载的内容也是一个大大的中间工具,当我们完成文件编写点击运行后,这个工具对 NodeJS 文件内容做了一层转换,让它能够顺利被计算机执行。
这和后端语言很多、前端语言很少有啥关系呢?
从功能上来看,JS 开发的目的是能够在浏览器中进行一些校验和数据处理,和界面紧密相连,数据的处理都交由后端来做了,场景相对单一,所以开发语言的类型单一。(我猜的)
而后端想要将数据独立于程序的运行存起来,就必须把修改的数据写入硬盘中,然后对数据进行读取、查询。
所以,后端对于计算机的硬件操作更加频繁。语言种类多,应该是为了照顾各种场景。比如有些语言读写速度快,或者编译速度快等,虽然最后都转化成了机器语言,但侧重点各不相同。(还是我猜的)
NodeJS 和 JS 不可告人的关系
NodeJS 和 js 到底有什么关系呢?它们的关系就是,语法一致。
比如在 c 语言里定义整数得用 int, NodeJS 和 js 里都可以用 let。
这样一来,如果前端想学 JS , 可以说是无缝对接,完全没有戒断期和适应期的。
NodeJS 虽然语法与 Js 一致,但它具备文件读写功能。这就意味着我们可以储存独立的数据文件。
那就让我们把它当作可以用 JS 语法来操作的一个后端环境吧,只要下载了 NodeJS 库,按照一定的要求去写代码,我们就能够使用它搭建服务器,操作数据表,来完成它作为后端的功能。
NodeJS 行不行
那如果用 NodeJS 作为广义上的后端来开发项目,真的 OK 吗?
知己知彼,百战不殆。我们先来了解一下其他后端语言在开发商有什么优势。
以下内容来自于我的后端朋友,他说他编的。
C和C++,一般在嵌入式、游戏和操作系统中使用,因为这类场景对性能要求很高,C和C++性能本身就比较高;
做算法和科学技术很多使用Python,因为Python比较接近自然语言,而且够简洁,一般研究人员编程不熟练,所以选用Python比较多;
做Windows开发很多时候选用C#,.net, VB,因为这些是微软自己设计的语言,自然就比较适合进行Windows桌面程序开发;
Go 语言是谷歌 2009 年发布的第二款开源编程语言,它专门针对多处理器系统应用程序的编程进行了优化,它是一种系统语言其非常有用和强大,其程序可以媲美 C 或 C++ 代码的速度,而且更加安全、支持并行进程。
相比以上语言,NodeJS 作为后端语言的优势在哪呢?
完成服务器的搭建以后,一个服务器往往连接多个客户端。如果我们把服务端的内存看成一个房子,那么有些后端语言处理方式就是,一个客户端连接给它配一个服务人员,一对一,一对一的满足上门的任务要求(多线程处理)。
而 NodeJS 的处理方式是只派一个人,给上门的客户记录一下需求,转接到下一个处理流程,然后接待下一个客户。如果某个处理流程完了,就给对应客户通知一声,把结果给它。(单线程,异步)。
要知道,一个人就得占一个位置。这样子,NodeJS 的优势就体现出来了,就是它人少,所以它能用尽可能少的内存,连接尽可能多的客户。
所以,支持大量用户的并发连接,NodeJS 有优势。
因为它就那么一个人,不存在两个人都需要对方的资源才能执行下一步人物的情况(死锁)。但是这样有个缺点。如果使用多个人服务多个客户,如果有个客户特别难缠(计算量大),它非要你费好久才能理解它真正的需求,虽然耽误一个服务人员的时间,但是并不影响其他服务人员服务其他客户。
而 NodeJS 这个时候就麻烦了,它不得不处理,这么一处理,就耽误了后面的客户。
那么,什么软件,一起用的人又多,数据不需要经过大量计算、主要是写入读出呢?
没错,聊天软件。
还有那种专门提供后端接口的网站,也不错。主要是接到请求,返回数据。
游戏也会用到 NodeJS ,比如 Pinus, 它就是基于node.js的高性能,分布式游戏服务器框架。
毕竟。NodeJS 的底层是 C/C++ 编写的,所以它的执行速度有保障。
所以 NodeJS 行不行取决于它的应用场景,毕竟合适的才能长久。
NodeJS 不会告诉你,它还偷偷做了些什么
我们还是从熟悉的 JS 切入。
最开始接触前端,引用 JS 都是通过 script 标签。
这种形式在开发中带来的问题是,无论是自己写,还是引用,命名冲突带来的问题只有你想不到,没有它不存在。
而 Java 早就有了类文件。大学写 java 的时候,一个类文件我能够放置指定的数据和功能,在其他文件中引入该文件,进行下一步操作。在写的过程中,不仅能够规避命名问题,也能够让开发思路更加清晰、维护更加方便。
对比之下,js 看起来就有那么一点不上档次。在大型开发、复杂开发、多人开发上落后一截。随着业务越发复杂,参与人数变多,以前那种简单的小打小闹催生的问题越来越多。在这种情况下,出现了 CommonJS。
CommonJS
什么是 CommonJS ? 它到底怎么用?它的适用场景是什么?
相信大多数人接触到这个名词的时候,脑子里都和我一样,出现了疑问三连。
先来看一段来自于 CommonJS 规范 · Webpack 中文指南 的介绍:
CommonJS 是以在浏览器环境之外构建 JavaScript 生态系统为目标而产生的项目,比如在服务器和桌面环境中。
这个介绍至少可以解答我们的一个疑问:适用场景。
即,被 浏览器解析的 js 文件 不支持。
那么,它是个什么东西?
CommonJS 是一套规范,它的创建和核准是开放的。这个规范已经有很多版本和具体实现。
这个网站上的介绍,我们把它翻译一下,就是它并不是我们平时写浏览器端 JS 所理解的那种可以引用的库,不是一种事物,而是一种规范。比如学校规定早上八点钟上课,有些人骑车上学,有些人走路上学,有些人不上学。
那么八点钟上课,就是学校出的一个规范,这些去上学的人都支持这个规范,虽然遵守方式(实现过程) 不一样,但是他们最终表的结果:八点钟到学校 是一致 的,我们可以基于 一致的结果 再进行下一步的安排。很明显,不上学的人就是不支持。
比如浏览器,你用 commonJS 规定的语法去引入模块,浏览器读不了,因为它不遵守规范,所以没有结果。
NodeJS 项目严格遵守了这种规范。我们可以理解为,NodeJS 整个环境,它提供了一个接口或者怎么样,它能够读懂我们按照规范去写的代码,然后实现我们 使用这种规范 想要达到的运行结果。
说了这么多,相信你应该差不多理解了 commonJS 和 NodeJS 之间的关系。
那它在代码中是怎么体现的呢?
// moduleA.js
module.exports = function( value ){
return value * 2;
}
// moduleB.js
var multiplyBy2 = require('./moduleA');
var result = multiplyBy2(4);
最直观的体现是,它规定了导入模块和导出模块的写法。易于理解,也并不难记。
值得一提的是,CommonJS 是同步加载模块。就是说,如果同事写下 10 个 require,它会等到上一个模块加载完成之后再加载下一个模块。
这种看似简单的规范,意义非凡。我们不用再纠结于命名冲突,也重塑了我们模块化的思考方式 ,将功能模块化,然后分而治之。制定了这种规范后,我们可以就可以建立通用工具库,甚至基于这种规范,我们可以使用别人写好的工具库。而无论我们具体是怎么实现的,它的入口和出口是一致的。我们只需要遵从规范去调用它即可。
NodeJS 异步编程风格
同步和异步简述
什么是同步,什么是异步?
同步就是烧水的时候等着,等水烧开了我把它倒壶里了我才能扫地。任务必须等上一个完了,我才做下一个。
异步就是烧水的时候边扫地,扫着扫着,我听到水烧开的声音,我就先跑去把水倒了,完了我接着扫地。
即,当一个任务 A 需要等待的时候(发起请求),我先做点其他BCD任务。等到我得到一个信号,告诉我A任务做完了,我就接着做 A 任务。
NodeJS 的异步实现
如果你是按顺序阅读本文,那么从上文我的比喻中,我们可以意识到 NodeJS ,采用的是 异步。
那么 ,NodeJS 是怎么实现异步的呢?
主要有三种方式。
回调、Promise、async/await
前两种我就不做过多的叙述了,主要是它们的写法就是很容易让人理解这是个异步。而最后一种,它的写法,看起来像个同步。
虽然我在上文中举的例子让同步看起来像是一个不知变通的智障,不过比喻就是比喻实际是实际,比喻是为了让我们理解它的工作方式而不是鄙视之一。
在实际的编程里,还是同步好啊,好写啊,隐藏的问题少啊。
我举个例子,比如
data = 请求结果 R
拿到 R 做一个循环 得到 C
打印 C
这个看起来没啥毛病,但是!这个书写方式是同步的书写方式!同步会等到 data 拿到值以后再进行下一步,这个时候,同步其实更加符合我们的思考\书写习惯。
放异步呢?它可不管你,先把 C 打印出来再说。凡是依赖 data 的数据通通 GG!
虽然回调可以解决这个问题,但是依赖一多,回调就跟俄罗斯套娃似的,没完没了。写起来恶心看起来也恶心。
所以,出了 Promise 来解决这个问题,而 async/await 的写法则进一步贴进了同步的写法。
贴一段代码:
const getDetailInfo = async () => {
try {
const { data } = await http.post(API.WECHAT.getWeChatcfg());
const { secret } = data || {};
console.log(secret)
} catch (error) {
Toast.show(error);
}
};
怎么样,是不是看起来跟同步的思路非常相似?
虽然它写起来是个同步,但是并不改变 NodeJS 异步的核心哈,它只是把最开始的写法改了又改最终给我们写法上的方便,就好像经过厂家的努力,大豆吃起来具备肉的口感。
结语
你可能说,我*,怎么就结语了呢?不是说 Talk is cheap. Show me the code.(能动手不要动口)。
但是又说了,欲练此功,必先 …… 啊不,必先 磨刀,因为磨刀不误砍柴功。
我们只有了解了关于 NodeJS 的前世今生,我们才能消除对于它的那份陌生,后面进行下一步的时候才能更顺畅不是?
刀都磨了,砍柴还会远吗?下一篇,我们直接动手!
如果这篇文章对你有帮助,记得给我点赞噢~ 不然我会伤心的 ,OK?