Node.js入门:掌握4个核心JavaScript概念

作者:终端旅客

时间:2026-10-23

浏览:393

本文深入解析Node.js开发的四个基石:非阻塞异步I/O机制、JavaScript原型链继承、模块系统(核心与用户定义)以及回调函数原理。通过餐厅类比与代码示例,帮助初学者理解Node.js事件驱动架构的核心逻辑,为构建高性能服务器应用奠定坚实基础。

文章目录

Node.js是一个基于Chrome V8引擎构建的服务器端运行环境。尽管其底层由C++编写,但开发者主要通过JavaScript语言来编写应用程序逻辑。

为了有效掌握Node.js,以下四个核心概念至关重要。本文将简明扼要地逐一介绍这些基础知识点。

1. 非阻塞或异步I/O

作为服务器端框架,Node.js的核心任务之一是处理来自浏览器的请求。在传统阻塞式I/O系统中,服务器必须等待前一个请求的响应(如HTML页面)完全返回后,才能开始处理下一个请求。这种机制导致服务器在处理当前请求时会阻塞其他请求,从而增加浏览器的等待时间。

Node.js采用了不同的处理机制。当某个请求涉及耗时操作时,Node.js会将该请求放入事件循环(event loop)中挂起,随即继续处理调用栈(call stack)中的下一个请求。一旦挂起的请求完成处理,Node.js会收到通知,并将结果渲染返回给浏览器。

为了直观理解这一机制,我们可以参考以下示例:

阻塞式I/O示例


// take order for table 1 and wait...
var order1 = orderBlocking(['Coke', 'Iced Tea']);
// once order is ready, take order back to table.
serveOrder(order1);
// once order is delivered, move on to another table.
// take order for table 2 and wait...
var order2 = orderBlocking(['Coke', 'Water']);
// once order is ready, take order back to table.
serveOrder(order2);
// once order is delivered, move on to another table.
// take order for table 3 and wait...
var order3 = orderBlocking(['Iced Tea', 'Water']);
// once order is ready, take order back to table.
serveOrder(order3);
// once order is delivered, move on to another table.

以餐厅服务为例:服务员接受1号桌的点单后,必须站在旁边等待厨师完成菜品,随后才将菜端给顾客。在此期间,服务员无法接待其他顾客,导致资源浪费和等待时间延长。

非阻塞式I/O示例


// take order for table 1 and move on...
orderNonBlocking(['Coke', 'Iced Tea'], function(drinks){
 return serveOrder(drinks);
});
// take order for table 2 and move on...
orderNonBlocking(['Beer', 'Whiskey'], function(drinks){
 return serveOrder(drinks);
});
// take order for table 3 and move on...
orderNonBlocking(['Hamburger', 'Pizza'], function(food){
 return serveOrder(food);
});

在非阻塞模式下,服务员接收1号桌点单后,立即告知厨师,随即返回接受其他桌位的点单。当1号桌的菜品准备好时,服务员再将其送上。这种方式确保了服务员不会因等待单一订单而阻塞对其他顾客的服务,从而提高了整体效率。

2. 原型

原型(Prototype)是JavaScript中较为复杂但至关重要的概念。由于在Node.js开发中频繁使用原型机制,每位JavaScript开发者都必须深入理解这一概念。

在Java或C++等支持经典继承的语言中,代码重用通常通过定义类并创建对象或继承该类来实现。然而,JavaScript没有“类”的概念。相反,JavaScript通过创建对象,并基于现有对象扩展出新对象或创建新对象来实现代码复用,这被称为原型继承。

在JavaScript中,每个对象都链接到一个原型对象,从而继承其属性。虽然原型在功能上类似于其他面向对象语言中的类,但原型本身也是一个对象。所有对象最终都链接到Object.prototype,后者由JavaScript引擎预定义。

当通过obj.propName或obj['propName']访问属性时,如果对象自身不具备该属性(可通过obj.hasOwnProperty('propName')验证),JavaScript运行时会沿原型链向上查找。若原型链中不存在该属性,最终会返回undefined。

通过以下代码示例可以更深入地理解这一机制:


if (typeof Object.create !== 'function') {
  Object.create = function (o) {
    var F = function () {};
    F.prototype = o;
    return new F();
  };
var otherPerson = Object.create(person);

创建新对象时,需指定其原型。示例中向Object函数添加了一个方法,该方法接收另一个对象作为参数,并创建一个以该对象为原型的新对象。

修改新对象本身不会影响其原型;然而,若修改原型对象,所有基于该原型的对象都会反映出这些变化。

原型机制较为复杂,后续文章将对此进行更详细的展开说明。

3. 模块

如果你熟悉Java中的包(Package),那么Node.js中的模块概念与之类似。模块本质上是包含特定功能代码的JavaScript文件。采用模块模式有助于提高代码的可读性和可维护性。使用模块时,需在JavaScript文件中通过特定方式引入,类似于Java中导入包的操作。

Node.js主要包含两种类型的模块:

核心模块:这些模块随Node.js库预编译提供。其目的是封装开发者常用且重复的代码片段,避免重复造轮子。常见的核心模块包括HTTP、URL、EVENTS、FILE SYSTEM等。

用户定义模块:这是开发者为特定应用需求在应用程序内部创建的模块。当核心模块无法满足特定功能需求时,需使用用户定义模块。

模块通过require函数加载。若为核心模块,参数仅为模块名称;若为用户定义模块,参数则为该模块在文件系统路径。示例如下:


// extract a core module like this
var http = require('http);
// extract a user defined module like this
var something = require('./folder1/folder2/folder3/something.js');

4. 回调函数

在JavaScript中,函数被视为“一等公民”(First-class object)。这意味着函数可以像普通对象一样操作:赋值给变量、作为参数传递给其他方法、声明为对象属性,甚至从函数中返回。

回调函数是JavaScript中的一种匿名函数,它可以作为参数传递给其他函数,由调用方决定何时执行或返回。这是回调函数——这一最广泛使用的函数式编程范式的基础。

当将回调函数作为参数传递时,我们仅传递函数定义,而不确定其执行时机。具体执行时间完全取决于调用函数的机制。回调函数会在稍后的某个时间点“回调”执行,这也是Node.js非阻塞或异步行为的根本基础。示例如下:


setTimeout(function() {
  console.log("world");
}, 2000)
console.log("hello");

这是一个最简单的回调示例。我们将一个匿名函数作为参数传递给setTimeout函数,该函数仅负责在控制台输出日志。虽然函数定义明确,但执行时间由第二个参数(2000毫秒)决定。

执行顺序为:首先控制台输出第二条日志语句,随后在2秒后,回调函数中的日志语句才会输出。


// output
hello
world

上述四个JavaScript概念是Node.js新手必须掌握的核心要点。基础越扎实,应用越灵活,请务必牢记这些基础知识。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章