NodeJS是什么
- Node.js is a JavaScript runtime built on Chrome’s V8 ( JS运行时 )
- Node.js uses an event-driven , non-blocking I/O model ( 事件驱动、非阻塞I/O )
NodeJS的单线程
- 单线程只是针对主进程,I/O操作系统底层是多线程调度
- 单线程并不是单进程
补充知识:
1.进程:计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位
2.线程:进程内一个相对独立的、可调度的执行单元,与同属一个进程的线程共享进程的资源
NodeJS常用场景
- Web Server
- 本地代码构建
- 实用工具开发
环境
- CommonJS
- 每个文件都是一个模块,有自己的作用域
- 在模块内部 module 变量代表模块本身
- module.exports 属性代表模块对外的接口
- global
- process
require 规则
- / 表示绝对路径,./表示相对于当前文件的路径
- 支持 js、json、node扩展名,不写就依次尝试
- 不写路径只写名字则认为是 build-in 模块 或者各级 node_modules
require 特性
- module 被加载的时候执行,加载后缓存。(第一次加载的时候会执行代码,第二次就不再执行代码而是被缓存下来)
- 一旦出现某个模块被循环加载,就只输出已经执行的部分,还未执行的部分不会输出
module.exports 和 exports的区别
1 | const exports=module.exports; //exports是module.exports的快捷方式 |
global 全局对象
- CommonJS
- Buffer、process、console
- timer
基础API
- path
- 和路径有关的一切
- path.basename path.extname path.delimiter path.sep path.format path.parse path.resolve path.join path.normalize
注意点:
1. dirname、 filename总是返回文件的绝对路径
2.process.cwd()总是返回执行node 命令所在文件夹
3.对于”./“ ,在require方法中总是相对当前文件所在的文件夹;在其他地方和 process.cwd()一样,相对 node 启动文件夹
Buffer
挂载在全局对象global上
Buffer 用于处理二进制数据流
- 实例类似整数数组,大小固定
- C++ 代码在V8堆外分配物理内存
events
所有能触发事件的对象都是
EventEmitter
类的实例。 这些对象有一个eventEmitter.on()
函数,用于将一个或多个函数绑定到命名事件上。 事件的命名通常是驼峰式的字符串。eventEmitter.on()
用于注册监听器,eventEmitter.emit()
用于触发事件。
1
2
3
4
5
6
7
8
9const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('触发事件');
});
myEmitter.emit('event');fs
- 所有文件系统操作都具有同步和异步的形式。
- 异步的形式总是将完成回调作为其最后一个参数。 传给完成回调的参数取决于具体方法,但第一个参数始终预留用于异常。 如果操作成功完成,则第一个参数将为
null
或undefined
。
1
2
3
4
5
6const fs = require('fs');
fs.unlink('/tmp/hello', (err) => {
if (err) throw err;
console.log('已成功删除 /tmp/hello');
});
cli 版本号
- 格式:x.y.z fix bugs的时候升级z位。新增兼容功能的时候升级y位。新增功能,不保证兼容,是新的API的时候升级x位。 如果只是修复bug,需要更新z位。如果是新增了功能,但是向下兼容,需要更新y位。如果有大变动,向下不兼容,需要更新x位。
- 1.2.*等价于~1.2.0 自动升级z位,x、y位固定
- 2.x等价于^2.0.0 自动升级y、z位,x位固定,大版本不任意升级
~
会匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x版本,但是不包括1.3.0^
会匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0
面试题
1、node有哪些特征,与其他服务器端对比
特征:单线程、事件驱动、非阻塞I/O
node 比其他服务端性能更好,速度更快
2、CommonJS中require/exports和ES6中import/export区别
- 前者不支持动态导入,后者支持
- 前者是异步导入,因为用于浏览器,需要下载文件,如果采用同步导入会对渲染有很大影响; 后者是同步导入,因为用于服务器,文件都在本地
- 前者采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会随导出值变化;后者在导出时都是值拷贝,就算导出值改变了,导入值也不会改变。如果想更新值,就要重新导入一次
- ES Module 会编译成 require/exports 来执行
3、谈谈对node.js npm webpack的理解
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
npm全称为Node Package Manager,是一个基于Node.js的包管理器,也是整个Node.js社区最流行、支持的第三方模块最多的包管理器。
npm的使用场景:
- 允许用户获取第三方包并使用。
- 允许用户将自己编写的包或命令行程序进行发布分享。
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
4、使用npm有哪些好处?
通过NPM,你可以安装和管理项目的依赖,并且能够指明依赖项的具体版本号,可以通过package.json文件来管理项目信息,配置脚本
5、AMD CMD规范的区别
CommonJS和AMD都是JavaScript模块化规范
CMD依赖就近,而AMD依赖前置
CMD是延迟执行的,而AMD是提前执行的
6、如何判断当前脚本运行在浏览器还是node环境中
通过判断 Global 对象是否为 window ,如果不为window ,当前脚本没有运行在浏览器中
7、简述同步和异步的区别,如何避免回调地狱
同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为
异步方法调用一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而异步方法通常会在另外一个线程中,整个过程,不会阻碍调用者的工作
避免回调地狱:
1)Promise
2)async/await
3)generator
4)事件发布/监听模式
8、几种常见模块化规范的简介
AMD/CMD 主要用于浏览器
- Asynchronous Module Definition(AMD 异步模块定义) RequireJS在推广过程中对模块定义的规范化产出。特点是依赖前置,会先尽早地执行依赖
- Common Module Definition(CMD 公共模块定义) SeaJS在推广过程中对模块定义的规范化产出。特点是依赖就近,延迟执行。
CommonJS 主要用于服务器
- NodeJS是CommonJS规范的实现,webpack也是以CommonJS的形式写的
ES6 Module 浏览器和服务器通用的模块解决方案
两个命令构成:import 和 export
ES6 Module 与 CommonJS的区别
前者不支持动态导入,后者支持
前者是异步导入,因为用于浏览器,需要下载文件,如果采用同步导入会对渲染有很大影响; 后者是同步导入,因为用于服务器,文件都在本地
前者采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会随导出值变化;后者在导出时都是值拷贝,就算导出值改变了,导入值也不会改变。如果想更新值,就要重新导入一次
ES Module 会编译成 require/exports 来执行
9、app.use和app.get区别
app.use(path,callback)中的callback既可以是router(路由)对象又可以是函数
app.get(path,callback)中的callback只能是函数
10、说一下事件循环eventloop
六个阶段:timers,pending callbacks,idle、prepare,poll,check,close callbacks
执行顺序:按阶段顺序执行,并且每一阶段结束都要查询是否存在微任务,若存在,则全部执行(nextTick优先)
timers 执行setTimeout、setInterval
poll 1.回到timers阶段执行回调2.执行I/O回调
check 执行setImmediate
11、node怎么跟MongoDB建立连接
1)引入mongoose
2)使用mongoose.connect()方法连接到MongoDB数据库
3)监听连接是否成功
4)然后通过node,书写接口,对数据库进行增删改查
1 | var mongoose=require('mongoose'); |
12、KOA
主要是async和await,下面是简单实现一个async函数
1 | function spawn(genF) { |
Express
路由
支持类型
- 字符串类型
- 字符串模式类型
- 正则表达式类型
- 参数类型
路由拆分
- 路由拆分前,无论是新增还是修改路由,都要带着
/user
前缀,这对于代码的可维护性来说是大忌。
- 路由拆分前,无论是新增还是修改路由,都要带着
1 | var express = require('express'); |
- 利用
express.Router()
进行了路由拆分,新增、修改路由都变得极为便利
1 | var express = require('express'); |
中间件
- 中间件其实是一个函数,在响应发送之前对请求进行一些操作
- express内部维护一个函数数组,这个函数数组表示在发出响应之前要执行的所有函数,也就是中间件数组。
- 使用
app.use(fn)
后,传进来的fn
就会被扔到这个数组里,执行完毕后调用next()
方法执行函数数组里的下一个函数,如果没有调用next()
的话,就不会调用下一个函数了,也就是说调用就会被终止。
1 | //实现原理 |
模板引擎
jade
ejs
语法
- 1.<% code %>用于执行其中javascript代码
- 2.<%= code %>会对code进行html转义
- 3.<%- code %> 注释
类似于JSP
四大作用域:page、request、session、application
九大内置对象:page、config、application、request、response、session、out、exception、pageContext
指令
格式:<%@ directive {attribute=value} %>
例子
language
<%@ page language=”java” contentType=”text/html charset=UTF-8” pageEncoding=”UTF-8”%>
import
<%@ page import=”java.util.List,java.util.ArrayList”%>include
<%@ include file=”relativeURL”%>
行为
- 格式:<jsp:elements {attribute=”value”}/>
- <jsp:include />行为
- <jsp:forward />行为
- Java bean行为,包括useBean行为、setProperty行为、getProperty行为
语法
- 1.使用<% 编写java代码 %>,中间java代码必须遵循Java语法
- 2.使用<%=xxx %>来输出结果
- 3.使用 <%– –%> 来注释