百度工程师如何带你深入探索Node.js在搜索引擎中的应用?
- 内容介绍
- 文章标签
- 相关推荐
本文共计2544个文字,预计阅读时间需要11分钟。
作者 | Candy | 导读如果你是一个前端程序员,不懂PHP、Python或Ruby等动态编程语言,但又想创建自己的服务,那么Node.js是一个非常不错的选择。Node.js是运行在服务器端的JavaScript,它允许你使用JavaScript编写服务器端代码,从而实现前后端分离的开发模式。
作者 | 糖果candy
导读
如果你是一个前端程序员,你不懂得像PHP、Python或Ruby等动态编程语言,然后你想创建自己的服务,那么Node.js是一个非常好的选择。
Node.js 是运行在服务端的 JavaScript,如果你熟悉Javascript,那么你将会很容易学会Node.js。
当然,如果你是后端程序员,想部署一些高性能的服务,那么学习Node.js也是一个非常好的选择。
全文6723字,预计阅读时间17分钟。
01 什么是Node.js?
我们先看一下官方对Node.js的定义:Node.js是一个基于V8 JavaScript引擎的JavaScript运行时环境。
但是这句话可能有点笼统:
1、什么是JavaScript运行环境?
2、为什么JavaScript需要特别的运行环境呢?
3、什么又是JavaScript引擎?
4、什么是V8?
带着这些疑问我们先了解一下nodejs的历史,在 Node.js 出现之前,最常见的 JavaScript 运行时环境是浏览器,也叫做 JavaScript 的宿主环境。浏览器为 JavaScript 提供了 DOM API,能够让 JavaScript 操作浏览器环境(JS 环境)。
2009 年初 Node.js 出现了,它是基于 Chrome V8 引擎开发的 JavaScript 运行时环境,所以 Node.js 也是 JavaScript 的一种宿主环境。而它的底层就是我们所熟悉的 Chrome 浏览器的 JavaScript 引擎,因此本质上和在 Chrome 浏览器中运行的 JavaScript 并没有什么区别。但是,Node.js 的运行环境和浏览器的运行环境还是不一样的。
通俗点讲,也就是说Node.js基于V8引擎来执行JavaScript的代码,但是不仅仅只有V8引擎。
我们知道V8可以嵌入到任何C++应用程序中,无论是Chrome还是Node.js,事实上都是嵌入了V8引擎来执行JavaScript代码,但是在Chrome浏览器中,还需要解析、渲染HTML、CSS等相关渲染引擎,另外还需要提供支持浏览器操作的API、浏览器自己的事件循环等。
另外,在Node.js中我们也需要进行一些额外的操作,比如文件系统读/写、网络IO、加密、压缩解压文件等操作。
那么接下来我们来看一下浏览器是如何解析渲染的。
02 浏览器是怎么渲染一个页面的?
浏览器渲染一个网页,简单来说可以分为以下几个步骤:
- HTML 解析:在这个过程之前,浏览器会进行 DNS 解析及 TCP 握手等网络协议相关的操作,来与用户需要访问的域名服务器建议连接,域名服务器会给用户返回一个 HTML 文本用于后面的渲染 (这一点很关键,要注意)。
- 渲染树的构建:浏览器客户端在收到服务端返回的 HTML 文本后,会对 HTML 的文本进行相关的解析,其中 DOM 会用于生成 DOM 树来决定页面的布局结构,CSS 则用于生成 CSSOM 树来决定页面元素的样式。如果在这个过程遇到脚本或是静态资源,会执行预加载对静态资源进行提前请求,最后将它们生成一个渲染树。
- 布局:浏览器在拿到渲染树后,会进行布局操作,来确定页面上每个对象的大小和位置,再进行渲染。
- 渲染:我们电脑的视图都是通过 GPU 的图像帧来显示出来的,渲染的过程其实就是将上面拿到的渲染树转化成 GPU 的图像帧来显示。首先,浏览器会根据布局树的位置进行栅格化(用过组件库的同学应该不陌生,就是把页面按行列分成对应的层,比如 12 栅格,根据对应的格列来确定位置),最后得到一个合成帧,包括文本、颜色、边框等;其次,将合成帧提升到 GPU 的图像帧,进而显示到页面中,就可以在电脑上看到我们的页面了。
相信看到这里,大家对浏览器怎么渲染出一个页面已经有了大致的了解。页面的绘制其实就是浏览器将 HTML 文本转化为对应页面帧的过程,页面的内容及渲染过程与第一步拿到的 HTML 文本是紧密相关的。
03 事件循环和异步IO
首先要了解事件循环是什么?那么我们先了解进程和线上的概念。
- 进程和线程:都是操作系统的概念。
- 进程:计算机已经运行的程序,线程:操作系统能够调度的最小单位启动一个应用默认是开启一个进程(也可能是多进程)。
每一个进程中都会启动一个线程用来执行程序中的代码,这个线程称为主线程。
举例子:比如工厂相当于操作系统,工厂里的车间相当于进程,车间里的工人相当于是线程,所以进程相当于是线程的容器。
那么浏览器是一个进程吗?它里面是只有一个线程吗?
目前浏览器一般都是多进程的,一般开启一个tab就会开启一个新的进程,这个是防止一个页面卡死而造成的所有页面都无法响应,整个浏览器需要强制退出。
其中每一个进程当中有包含了多个线程,其中包含了执行js代码的线程。
js代码是在一个单独的线程中执行的,单线程同一时间只能做一件事,如果这件事非常耗时,就意味着当前的线程会被阻塞,浏览器时间循环维护两个队列:宏任务队列和微任务队列。
- 宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等;
- 微任务队列(microtask queue):Promise的then回调。
那么事件循环对于两个队列的优先级是怎么样的呢?
new promise()是同步,promise.then,promise.catch,resolve,reject 是微任务。
04 使用事件驱动程序
Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。
这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。
Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:
// 引入 events 模块var events = require('events');// 创建 eventEmitter 对象var eventEmitter = new events.EventEmitter();以下程序绑定事件处理程序:
// 绑定事件及事件的处理程序eventEmitter.on('eventName', eventHandler);我们可以通过程序触发事件:
// 触发事件eventEmitter.emit('eventName');实例
创建 main.js 文件,代码如下所示:
// 引入 events 模块var events = require('events');// 创建 eventEmitter 对象var eventEmitter = new events.EventEmitter();// 创建事件处理程序var connectHandler = functionconnected() { console.log('连接成功~~~'); // 触发 data_received 事件 eventEmitter.emit('data_received');}// 绑定 connection 事件处理程序eventEmitter.on('connection', connectHandler);// 使用匿名函数绑定 data_received 事件eventEmitter.on('data_received', function(){ console.log('数据接收完毕。');});// 触发 connection 事件 eventEmitter.emit('connection');console.log("程序执行完毕。");接下来让我们执行以上代码:
$ node main.js连接成功~~~数据接收完毕。程序执行完毕。05 Node.js架构以及与浏览器的区别
上图是 Node.js 的基本架构,我们可以看到,(Node.js 是运行在操作系统之上的),它底层由 V8 JavaScript 引擎,以及一些 C/C++ 写的库构成,包括 libUV 库、c-ares、llm.runoob.com/nodejs/nodejs-global-object.html
——END——
参考资料:
[1]juejin.cn/post/6844903504931209224
[2]nodejs.org/zh-cn/docs/guides/
[3]部分图片来源于稀土掘金网站
推荐阅读:
揭秘百度智能测试在测试定位领域实践
百度工程师带你探秘C++内存管理(ptmalloc篇)
为什么 OpenCV 计算的视频 FPS 是错的
百度 Android 直播秒开体验优化
iOS SIGKILL 信号量崩溃抓取以及优化实践
如何在几百万qps的网关服务中实现灵活调度策略
本文共计2544个文字,预计阅读时间需要11分钟。
作者 | Candy | 导读如果你是一个前端程序员,不懂PHP、Python或Ruby等动态编程语言,但又想创建自己的服务,那么Node.js是一个非常不错的选择。Node.js是运行在服务器端的JavaScript,它允许你使用JavaScript编写服务器端代码,从而实现前后端分离的开发模式。
作者 | 糖果candy
导读
如果你是一个前端程序员,你不懂得像PHP、Python或Ruby等动态编程语言,然后你想创建自己的服务,那么Node.js是一个非常好的选择。
Node.js 是运行在服务端的 JavaScript,如果你熟悉Javascript,那么你将会很容易学会Node.js。
当然,如果你是后端程序员,想部署一些高性能的服务,那么学习Node.js也是一个非常好的选择。
全文6723字,预计阅读时间17分钟。
01 什么是Node.js?
我们先看一下官方对Node.js的定义:Node.js是一个基于V8 JavaScript引擎的JavaScript运行时环境。
但是这句话可能有点笼统:
1、什么是JavaScript运行环境?
2、为什么JavaScript需要特别的运行环境呢?
3、什么又是JavaScript引擎?
4、什么是V8?
带着这些疑问我们先了解一下nodejs的历史,在 Node.js 出现之前,最常见的 JavaScript 运行时环境是浏览器,也叫做 JavaScript 的宿主环境。浏览器为 JavaScript 提供了 DOM API,能够让 JavaScript 操作浏览器环境(JS 环境)。
2009 年初 Node.js 出现了,它是基于 Chrome V8 引擎开发的 JavaScript 运行时环境,所以 Node.js 也是 JavaScript 的一种宿主环境。而它的底层就是我们所熟悉的 Chrome 浏览器的 JavaScript 引擎,因此本质上和在 Chrome 浏览器中运行的 JavaScript 并没有什么区别。但是,Node.js 的运行环境和浏览器的运行环境还是不一样的。
通俗点讲,也就是说Node.js基于V8引擎来执行JavaScript的代码,但是不仅仅只有V8引擎。
我们知道V8可以嵌入到任何C++应用程序中,无论是Chrome还是Node.js,事实上都是嵌入了V8引擎来执行JavaScript代码,但是在Chrome浏览器中,还需要解析、渲染HTML、CSS等相关渲染引擎,另外还需要提供支持浏览器操作的API、浏览器自己的事件循环等。
另外,在Node.js中我们也需要进行一些额外的操作,比如文件系统读/写、网络IO、加密、压缩解压文件等操作。
那么接下来我们来看一下浏览器是如何解析渲染的。
02 浏览器是怎么渲染一个页面的?
浏览器渲染一个网页,简单来说可以分为以下几个步骤:
- HTML 解析:在这个过程之前,浏览器会进行 DNS 解析及 TCP 握手等网络协议相关的操作,来与用户需要访问的域名服务器建议连接,域名服务器会给用户返回一个 HTML 文本用于后面的渲染 (这一点很关键,要注意)。
- 渲染树的构建:浏览器客户端在收到服务端返回的 HTML 文本后,会对 HTML 的文本进行相关的解析,其中 DOM 会用于生成 DOM 树来决定页面的布局结构,CSS 则用于生成 CSSOM 树来决定页面元素的样式。如果在这个过程遇到脚本或是静态资源,会执行预加载对静态资源进行提前请求,最后将它们生成一个渲染树。
- 布局:浏览器在拿到渲染树后,会进行布局操作,来确定页面上每个对象的大小和位置,再进行渲染。
- 渲染:我们电脑的视图都是通过 GPU 的图像帧来显示出来的,渲染的过程其实就是将上面拿到的渲染树转化成 GPU 的图像帧来显示。首先,浏览器会根据布局树的位置进行栅格化(用过组件库的同学应该不陌生,就是把页面按行列分成对应的层,比如 12 栅格,根据对应的格列来确定位置),最后得到一个合成帧,包括文本、颜色、边框等;其次,将合成帧提升到 GPU 的图像帧,进而显示到页面中,就可以在电脑上看到我们的页面了。
相信看到这里,大家对浏览器怎么渲染出一个页面已经有了大致的了解。页面的绘制其实就是浏览器将 HTML 文本转化为对应页面帧的过程,页面的内容及渲染过程与第一步拿到的 HTML 文本是紧密相关的。
03 事件循环和异步IO
首先要了解事件循环是什么?那么我们先了解进程和线上的概念。
- 进程和线程:都是操作系统的概念。
- 进程:计算机已经运行的程序,线程:操作系统能够调度的最小单位启动一个应用默认是开启一个进程(也可能是多进程)。
每一个进程中都会启动一个线程用来执行程序中的代码,这个线程称为主线程。
举例子:比如工厂相当于操作系统,工厂里的车间相当于进程,车间里的工人相当于是线程,所以进程相当于是线程的容器。
那么浏览器是一个进程吗?它里面是只有一个线程吗?
目前浏览器一般都是多进程的,一般开启一个tab就会开启一个新的进程,这个是防止一个页面卡死而造成的所有页面都无法响应,整个浏览器需要强制退出。
其中每一个进程当中有包含了多个线程,其中包含了执行js代码的线程。
js代码是在一个单独的线程中执行的,单线程同一时间只能做一件事,如果这件事非常耗时,就意味着当前的线程会被阻塞,浏览器时间循环维护两个队列:宏任务队列和微任务队列。
- 宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM监听、UI Rendering等;
- 微任务队列(microtask queue):Promise的then回调。
那么事件循环对于两个队列的优先级是怎么样的呢?
new promise()是同步,promise.then,promise.catch,resolve,reject 是微任务。
04 使用事件驱动程序
Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。
当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。
这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
整个事件驱动的流程就是这么实现的,非常简洁。有点类似于观察者模式,事件相当于一个主题(Subject),而所有注册到这个事件上的处理函数相当于观察者(Observer)。
Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件,如下实例:
// 引入 events 模块var events = require('events');// 创建 eventEmitter 对象var eventEmitter = new events.EventEmitter();以下程序绑定事件处理程序:
// 绑定事件及事件的处理程序eventEmitter.on('eventName', eventHandler);我们可以通过程序触发事件:
// 触发事件eventEmitter.emit('eventName');实例
创建 main.js 文件,代码如下所示:
// 引入 events 模块var events = require('events');// 创建 eventEmitter 对象var eventEmitter = new events.EventEmitter();// 创建事件处理程序var connectHandler = functionconnected() { console.log('连接成功~~~'); // 触发 data_received 事件 eventEmitter.emit('data_received');}// 绑定 connection 事件处理程序eventEmitter.on('connection', connectHandler);// 使用匿名函数绑定 data_received 事件eventEmitter.on('data_received', function(){ console.log('数据接收完毕。');});// 触发 connection 事件 eventEmitter.emit('connection');console.log("程序执行完毕。");接下来让我们执行以上代码:
$ node main.js连接成功~~~数据接收完毕。程序执行完毕。05 Node.js架构以及与浏览器的区别
上图是 Node.js 的基本架构,我们可以看到,(Node.js 是运行在操作系统之上的),它底层由 V8 JavaScript 引擎,以及一些 C/C++ 写的库构成,包括 libUV 库、c-ares、llm.runoob.com/nodejs/nodejs-global-object.html
——END——
参考资料:
[1]juejin.cn/post/6844903504931209224
[2]nodejs.org/zh-cn/docs/guides/
[3]部分图片来源于稀土掘金网站
推荐阅读:
揭秘百度智能测试在测试定位领域实践
百度工程师带你探秘C++内存管理(ptmalloc篇)
为什么 OpenCV 计算的视频 FPS 是错的
百度 Android 直播秒开体验优化
iOS SIGKILL 信号量崩溃抓取以及优化实践
如何在几百万qps的网关服务中实现灵活调度策略

