Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。将libuv作为跨平台抽象层,libuv是用c/c++写成的高性能事件驱动的程序库。nodejs的原理类似c/c++系统编程中的epoll
(1)V8引擎解析JavaScript脚本。
(2)解析后的代码,调用Node API。
(3)libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。
(4)V8引擎再将结果返回给用户。
nodejs 执行之后会初始化一个事件循环,执行代码程序(这些程序可能会造成异步调用、定时器或者process.nextTick()),然后开始执行事件循环。
上边的每一个模块都是事件循环的一个阶段,每个阶段都有一个要执行的回调的FIFO队列。虽然每个阶段都不同,一般来说,当事件执行到一个阶段,先执行这个阶段特有的操作,然后操作这个阶段的队列,当队列执行完或者达到了回调上限,事件循环就会执行下一个阶段。
小结:poll队列为空的时候,事件循环有可能执行check阶段执行setImmediate的回调,也有可能回到timer阶段执行setTimeout的回调,这取决于setImmediate和setTimeout的回调哪个到得早。
Node.js采用单线程模型,但通过事件循环和异步I/O操作,可以处理大量的并发请求。Node.js的事件循环是单线程的,但是通过内部的libuv库进行异步I/O操作,它可以同时处理数以万计的并发连接。
使用require方法导入模块
注意:requier函数有两个作用:
执行导入的模块中的代码 返回导入模块中的接口对象 module.exports
导入自定义模块时,require 参数是模块的路径。例如:const getDir = require(‘./getDir’)
路径中后缀名 .js 可以省略 相对路径"./xxx",不能省略 “./”,表示当前路径下的 xxx 文件 绝对路径"/xxx",表示当前磁盘根目录下的 xxx 文件,其中"/" 表示当前磁盘根目录
导入具名的核心模块,require 参数直接写模块名即可。例如:const http = require(‘http’)
导入第三方包时,require 参数就是下载第三方包时的包名。例如:const express = require(‘express’)
require 优先从缓存中加载模块,从缓存中加载时不会执行模块中的代码
一个模块中的JS代码仅在模块第一次被使用时执行一次,并且在使用的过程中进行初始化,之后缓存起来便于后续继续使用。
内置模块的加载优先级最高,例如 require(‘http’) 始终会返回内置的 fs 模块,即使在 node_modules 目录下有相同的包名叫 fs。
内置模块或者第三方模块,直接require 模块名即可。对于自定义模块,必须指定以 ./ 或 …/ 开头的路径标识符。
同时,在使用 require 导入自定义模块时,可以省略文件的扩展名。此时,Node.js 会按以下顺序分别尝试加载文件:
洋葱模型中间件机制
Koa框架使用异步编程风格,通过使用Promise或async/await等机制来处理异步操作。相比传统的回调方式,异步编程使得代码更加清晰、易于维护,并且能够避免回调地狱的问题。
Koa的核心思想是中间件,它允许开发者通过编写各种中间件来处理请求和响应。每个中间件可以单独执行特定的任务,也可以将控制权传递给下一个中间件。这种中间件的处理流程类似于洋葱模型,非常灵活。
Koa使用ES6中的生成器函数(Generator Function)来实现中间件的处理流程。生成器函数可以通过yield关键字暂停和恢复执行,这样就可以方便地实现中间件的串联和控制流程。生成器函数的特性使得编写和理解中间件变得更加简单和直观。
在Koa中,每个请求都会创建一个上下文对象(Context),它封装了请求和响应的相关信息,并提供了一些方便的方法来操作和获取请求和响应的内容。上下文对象还可以在中间件之间传递数据和状态,使得开发者能够更好地组织和管理代码。
本文作者:seek
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!