Ранее было собеседование, для фронтенд-разработчиков необходимо знать фоновый язык.
Мне задали столько вопросов в то время, хотя я не написал это в содержании статьи, вы можете взять эти вопросы для изучения и найти соответствующие ответы, что тоже своего рода улучшение!
- В чем разница между циклом событий браузера и циклом событий узла?
-
commonjs
изrequire
принцип реализации? - ES6
import
а такжеcommonjs
В чем разница между требовать? - рукописный
EventEmmit
Добрый
Для решения этих проблем будет опубликована последующая статья, и мы приветствуем всеобщее внимание.
Node
Зачем изучать Nodejs
- Потребности предприятия
- Опыт серверной разработки приветствуется
- инженер полного стека
- Базовые навыки веб-разработки
- Сервер
- внешний интерфейс
- Работа, связанная с эксплуатацией и развертыванием
Что такое узел
Node.js — это среда выполнения JavaScript, основанная на движке Chrome V8. Node.js используетуправляемый событиями,Неблокирующий ввод-выводмодель, что делает ее легкой и эффективной.
Текущая стабильная версия: 14.15.1 LTS (Long Term Support) версия с долгосрочной поддержкой.
установить узел
Официальная загрузка с сайта => установка в один клик, вы можете установить ее с небольшим количеством.
PS: Если учащиеся компьютера с Windows изменили путь установки во время установки, перейдите кИзменить переменные среды
Конечно, последняя версия узла 14.15.1, вы можете скачать последнюю версию и установить ее прямо сейчас.
Указывает, что установка прошла успешно
Готов к работе
-
запустить программу узла
console.log('hello node'); console.log('run my use:node 01-runnode');
Выполнить: узел 01-runnode.js
Каждый раз, когда вы изменяете файл js, вам нужно повторно запускать его, чтобы он вступил в силу.Установка nodemon может отслеживать изменения файла и перезапускаться автоматически.
npm i -g nodemon
беги позже с
nodemon 01-runnode.js
-
Программа узла отладки:
Debug-Start Debugging
REPL (интерактивный интерпретатор)
- Операция выражения
- использовать переменные
- многострочное выражение
- REPL-команда
- ctrl+c - выйти из текущего терминала.
- Дважды нажмите ctrl + c, чтобы выйти из Node REPL.
- ctrl + d - Выход из узла REPL.
- Клавиши вверх/вниз - просмотреть историю введенных команд
- клавиша табуляции - перечислить текущую команду
- .help - список команд использования
- .break — выйти из многострочного выражения
- .clear - выйти из многострочного выражения
- .save имя файла — сохранить текущую сессию Node REPL в указанный файл
- .load имя_файла — загрузить содержимое файла для текущего сеанса Node REPL.
Перезвоните
Непосредственным воплощением асинхронного программирования в Node.js является обратный вызов.
Асинхронное программирование полагается на обратные вызовы для достижения, но нельзя сказать, что программа асинхронна после использования обратных вызовов.
Функция обратного вызова будет вызвана после завершения задачи. Node использует большое количество функций обратного вызова. Все API Node поддерживают функции обратного вызова.
Например, мы можем выполнять другие команды во время чтения файла, а после того, как файл будет прочитан, мы возвращаем содержимое файла в качестве параметра функции обратного вызова. Таким образом, нет блокировки или ожидания файлов во время выполнения кода.I/O
работать. Это значительно улучшаетNode.js
производительность и может обрабатывать большое количество одновременных запросов.
код блокировки
// 阻塞式代码
const fs = require('fs');
const data = fs.readFileSync('01-runnode.js');
console.log(data.toString());
неблокирующий код
const fs = require('fs');
fs.readFile('01-runnode.j',function(err,data) {
if(err){
console.log(err.stack);
return;
}
console.log(data.toString());
});
console.log('继续执行');
Первый экземпляр выполняет программу после того, как файл был прочитан. Во втором примере нам не нужно ждать, пока файл будет прочитан, так что следующий код может выполняться одновременно с чтением файла, что значительно повышает производительность программы.
Поэтому блокировка выполняется по порядку, а неблокировка не обязательно должна быть по порядку, поэтому если нам нужно обработать параметры callback-функции, то это нужно прописать в callback-функции.
цикл событий
Node.js — однопоточное приложение с одним процессом, но поддерживает параллелизм через события и обратные вызовы, поэтому производительность очень высока.
Каждый API в Node.js является асинхронным и работает как отдельный поток, использует асинхронные вызовы функций и обрабатывает параллелизм.
В основном все механизмы событий в Node.js реализованы с использованием шаблона наблюдателя в шаблоне проектирования.
Одиночный поток Node.js аналогичен вводуwhile(true)
Цикл событий цикла событий до тех пор, пока наблюдатели событий не выйдут, каждое асинхронное событие генерирует наблюдатель событий, и функция обратного вызова вызывается, если происходит событие.
драйвер события
Node.js использует модель, управляемую событиями, когдаweb server
Когда запрос получен, он закрывается и обрабатывается перед обслуживанием следующего веб-запроса.
Когда запрос завершается, он возвращается в очередь обработки, а когда достигается начало очереди, результат возвращается пользователю.
Эта модель очень эффективна и масштабируема, потому чтоwebserver
Всегда принимайте запросы, не дожидаясь операций чтения или записи. (Это также известно как неблокирующий ввод-вывод или ввод-вывод, управляемый событиями).
В модели, управляемой событиями, создается основной цикл для прослушивания событий, и при обнаружении события запускается функция обратного вызова.
Весь управляемый событиями процесс реализован таким образом, что очень просто. Немного похожее на шаблон наблюдателя, событие эквивалентно субъекту (Subject), и все обработчики, зарегистрированные для этого события, эквивалентны наблюдателю (Observer).
Node.js имеет несколько встроенных событий. Мы можем привязывать и прослушивать события, вводя модуль событий и создавая экземпляр класса EventEmitter следующим образом:
Создайте 03-eventEmitter.js
// 引入event 模块
const events = require('events');
// 创建eventEmitter对象
const eventEmitter = new events.EventEmitter();
// 创建事件处理程序
const connectHandler = function connected() {
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('程序执行完毕');
воплощать в жизнь:
连接成功
数据接收成功
程序执行完毕
Буфер (буфер)
Сам язык JavaScript имеет только строковый тип данных, а не двоичный тип данных.
Но при работе с потоками, такими как TCP или файловые потоки, необходимо использовать двоичные данные. Итак, в Node.js определитеBuffer
Класс, который используется для создания области буфера, предназначенной для хранения двоичных данных.
В Node.jsBuffer
Классы — это основная библиотека, которая поставляется с ядром Node.Buffer
Библиотека предоставляет Node.js способ хранения необработанных данных, позволяя Node.js работать с двоичными данными, и всякий раз, когда данные, перемещаемые в операциях ввода-вывода, необходимо обрабатывать в Node.js, можно использоватьBuffer
библиотека. Необработанные данные хранятся вBuffer
в экземпляре класса. ОдинBuffer
Подобно массиву целых чисел, но он соответствует фрагменту необработанной памяти за пределами памяти кучи V8.
// buffer: 八位字节组成数组,可以有效的在js中存储二进制数据
// 创建
const buf1 = Buffer.alloc(10);
console.log(buf1);
// 通过数据创建
const buf2 = Buffer.from('hello world');
console.log(buf2);
const buf3 = Buffer.from([1,2,3]);
console.log(buf3);
// 写入
buf1.write('hello buffer');
console.log(buf1);
// 读取
console.log(buf2.toString());
console.log(buf2.toString('base64'));
// 合并
const buf4 = Buffer.concat([buf1,buf2]);
console.log(buf4.toString());
Поток (поток)
поток трубопровода
Каналы предоставляют механизм для потоков вывода во входные потоки. Обычно мы используем для получения данных из одного потока и передачи данных в другой поток.
Как показано на картинке выше, сравниваем файл с ведром с водой, а вода - это содержимое файла. Соединяем два ведра трубой так, чтобы вода перетекала из одного ведра в другое, так чтобы Медленно реализован процесс копирования больших файлов.
В следующем примере мы читаем содержимое одного файла и записываем содержимое в другой файл.
const fs = require('fs');
// 创建可读流
const readerStream = fs.createReadStream('./package.json');
// 创建可写流
const writerStream = fs.createWriteStream('./test.txt');
// 设置编码为utf8
readerStream.pipe(writerStream);
console.log('执行完毕');
цепной поток
Цепочка — это механизм создания цепочек операций с несколькими потоками путем соединения выходного потока с другим потоком. Сцепленные потоки обычно используются для конвейерных операций.
Затем мы используем каналы и цепочки для сжатия и распаковки файлов.
const fs = require('fs');
const zlib = require('zlib');
// 压缩test.txt为test.zip
fs.createReadStream('./test.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('test.zip'));
console.log('文件压缩成功');
модульная система
Чтобы файлы Node.js могли вызывать друг друга, Node.js предоставляет простую модульную систему.
Модули являются основными компонентами приложений Node.js, и между файлами и модулями существует однозначное соответствие. Другими словами, файл Node.js — это модуль, который может быть кодом JavaScript, JSON или скомпилированным расширением C/C++.
Модуль CommonJS
В Node.js создать модуль очень просто, создайте main.js
const Hello = require('./hello');
hello.world();
Node.js предоставляет два объекта: exports и require, где exports — это интерфейс, предоставляемый модулем, а require используется для получения интерфейса модуля извне, то есть объект exports полученного модуля.
Далее мы создадим файл hello.js со следующим кодом:
exports.world = function() {
console.log('hello world');
}
Иногда мы просто хотим инкапсулировать объект в модуль, формат выглядит следующим образом
module.exports = function() {
// ...
}
Например:
function Hello() {
let name;
this.setName = function(myName) {
name = myName
}
this.sayHello = function() {
console.log('hello', name);
}
}
module.exports = Hello;
Таким образом, вы можете получить объект напрямую:
const hello = new Hello();
hello.setName('小马哥');
hello.sayHello();
Единственное изменение в интерфейсе модуля — использованиеmodule.exports = Hello
вместоexports.world = function(){}
. Когда на модуль ссылаются извне, его интерфейсный объект должен быть выведенHello
сам объект, а не оригиналexports
.
Где находятся модули на стороне сервера
Как вы могли заметить, мы уже используем модули в нашем коде. так:
const fs = require('fs');
fs.createReadStream(...)
В Nodejs есть много часто используемых встроенных модулей, которые представлены в следующем разделе.
Node.jsrequire
Стратегия поиска файлов в методе следующая (обязательно к просмотру на собеседованиях, знакомых с механизмом поиска модулей)
Поскольку в Node.js есть 4 типа модулей (нативные модули и 3 типа файловых модулей), хотяrequire
Метод чрезвычайно прост, но внутренняя загрузка очень сложна, и ее приоритет загрузки также отличается. Как показано ниже:
Загрузка из кеша файлового модуля
Хотя нативные модули имеют другие приоритеты, чем файловые модули, ни один из них не будет иметь приоритета перед загружаемыми модулями, которые уже существуют из кэша файлового модуля.
Загрузка из родного модуля
Приоритет нативного модуля уступает только приоритету кеша файлового модуля. Метод require сначала проверяет, находится ли модуль в списке собственных модулей после разбора имени файла. Взяв в качестве примера модуль http, хотя в каталоге есть файл http/http.js/http.node/http.json, require("http") будет загружаться не из этих файлов, а из собственного модуля. Нативные модули также имеют область кеша, которая также предпочтительно загружается из области кеша. Если область кеша не была загружена, вызывается метод загрузки собственного модуля для загрузки и выполнения.
Загрузить из файла
Если кэш файлового модуля не существует и не является собственным модулем, Node.js анализирует параметры, переданные методом require, и загружает фактический файл из файловой системы. введен раздел, здесь мы подробно опишем процесс поиска файловых модулей, а также есть некоторые детали, которые стоит знать. Метод require принимает передачу следующих параметров:
- http, fs, путь и т. д., нативные модули.
- ./mod или ../mod, относительный путь к файловому модулю.
- /pathtomodule/mod, абсолютный путь к файлу module.
- mod, файловый модуль для неродных модулей.
Общие встроенные модули
модуль фс
Асинхронный и синхронный
открыть файл
fs.open(path, flags[, mode], callback)
параметр
-
путь - путь к файлу.
-
flags — поведение при открытии файла. Ниже приведены конкретные значения.
-
mode - Установить режим файла (разрешение), разрешение по умолчанию для создания файла 0666 (доступно для чтения, для записи).
-
callback - функция обратного вызова с двумя параметрами типа: callback(err, fd).
Параметр flags может принимать следующие значения:
Flag описывать r Откройте файл в режиме чтения. Выдает исключение, если файл не существует. r+ Откройте файл в режиме чтения-записи. Выдает исключение, если файл не существует. rs Синхронное чтение файлов. rs+ Чтение и запись файлов синхронно. w Откройте файл в режиме записи или создайте файл, если он не существует. wx Аналогично 'w', но запись файла завершается ошибкой, если путь к файлу существует. w+ Откройте файл в режиме чтения-записи или создайте файл, если он не существует. wx+ Аналогично 'w+', но чтение и запись файла завершаются ошибкой, если путь к файлу существует. a Откройте файл в режиме добавления или создайте файл, если он не существует. ax Аналогично 'a', но добавление файла завершается ошибкой, если путь к файлу существует. a+ Откройте файл в режиме добавления для чтения или создайте файл, если он не существует. ax+ Аналогично 'a+', но добавление чтения файла завершается ошибкой, если путь к файлу существует. записать в файл
fs.writeFile(filename, data[, options], callback)
Если файл существует, содержимое, записанное этим методом, перезаписывает старое содержимое файла.
Инструкции по использованию параметра следующие:
- path- Путь к файлу.
- data- Данные для записи в файл, который может быть объектом String (строка) или Buffer (поток).
- options- Параметр представляет собой объект, содержащий {кодировку, режим, флаг}. Кодировка по умолчанию — utf8, режим — 0666, флаг — «w».
- callback- Функция обратного вызова, функция обратного вызова содержит только параметр информации об ошибке (err) и возвращает значение при сбое записи.
прочитать файл
fs.read(fd, buffer, offset, length, position, callback)
закрыть файл
fs.close(fd, callback)
файл перехвата
fs.ftruncate(fd, len, callback)
Инструкции по использованию параметра следующие:
- fd- Дескриптор файла, возвращаемый методом fs.open().
- len- Длина содержимого файла, которое необходимо обрезать.
- callback- функция обратного вызова, без параметров
Удалить файлы
fs.unlink(path, callback)
Инструкции по использованию параметра следующие:
- path- Путь к файлу.
- callback- Функция обратного вызова, без параметров.
Создать каталог
fs.mkdir(path[, mode], callback)
-
path- Путь к файлу.
-
mode- Установите права доступа к каталогу, по умолчанию 0777.
-
callback- Функция обратного вызова, без параметров.
читать каталог
fs.readdir(path, callback)
Инструкции по использованию параметра следующие:
- path- Путь к файлу.
- callback- Функция настройки, функция обратного вызова с двумя параметрами ERR, FILES, ERR для сообщений об ошибках, файлы для файлов в списке каталогов
удалить каталог
fs.rmdir(path, callback)
Инструкции по использованию параметра следующие:
- path- Путь к файлу.
- callback- Функция обратного вызова, без параметров.
Как сделать асинхронный код синхронным
-
promise
const {promisify} = require('util'); const readFile = promisify(fs.readFile); readFile('./01-runnode.js').then(data=>console.log(data));
-
Promises API (версия узла выше 10.0)
const {promises} = require('fs'); promises.readFile('./01-runnode.js').then(data => console.log(data));
-
generator
const fs = require('fs'); const { promisify } = require('util'); const readFile = promisify(fs.readFile); function* read() { yield readFile('./01-runnode.js'); } let ge = read(); ge.next().value.then(data=>{ console.log(data); })
-
async
const fs = require('fs'); const {promisify} = require('util'); const readFile = promisify(fs.readFile); async function asyncReadFile() { let a = await readFile('./01-runnode.js'); console.log(a.toString()); } asyncReadFile();
ссылка на файловый модуль
ОС Модуль
const os = require('os');
// 系统内存总量
console.log(os.totalmem());
// 操作系统空闲内存量
console.log(os.freemem());
const mem = os.freemem() / os.totalmem() * 100;
console.log(`内存占有率${mem}%`);
Используйте сторонние модули
npm i cpu-stat -S
// 使用第三方模块
const cpuStat = require('cpu-stat');
cpuStat.usagePercent((err,percent)=>{
console.log(percent);
})
http-модуль
Суть Nodejs в том, чтобы быть веб-сервером, так как же заставить работать HTTP-сервер?
Быстро познакомимся с минималистичным, но не простым HTTP-сервером
const http = require('http');
http.createServer((req,res)=>{
res.end('响应完成了');
}).listen(3000);
запустить сервер
Доступ через браузер:http://localhost:3000
может видеть响应完成了
маршрутизация
Простой сервер выше не может удовлетворить наши потребности.Например, нам нужно получить доступ к разным адресам маршрутизации, чтобы найти разные страницы.Например:
доступ:http://localhost:3000/index
Чтобы просмотреть содержимое главной страницы, посетите:http://localhost:3000/about
хотел бы видеть контент о моей странице
доступ:http://localhost:3000/user
хочу увидеть данные json
const http = require('http');
const fs = require('fs');
http.createServer((req,res)=>{
const {url,method} = req;
if(url === '/index' && method === 'GET'){
// 读取首页
fs.readFile('./index.html',(err,data)=>{
if(err){
res.statusCode = 500;//服务器内部错误
res.end('500- Interval Serval Error!');
}
res.statusCode = 200;//设置状态码
res.setHeader('Content-Type','text/html');
res.end(data);
})
}else if(url === '/about' && method ==='GET'){
fs.readFile('./about.html', (err, data) => {
if (err) {
res.statusCode = 500;//服务器内部错误
res.end('500- Interval Serval Error!');
}
res.statusCode = 200;//设置状态码
res.setHeader('Content-Type', 'text/html');
res.end(data);
})
}else if(url ==='/user' && method === 'GET'){
res.statusCode = 200;//设置状态码
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify([{name:"小马哥"}]));
}else{
res.end();
}
}).listen(3000);
Простая версия для реализации собственного экспресса
Создать MExpress.js
const Application = require('./application');
function MExpress() {
return new Application();
}
module.exports = MExpress;
Создать приложение.js
// 需求
// 1.实现http服务器
// 2.实现get路由请求
const http = require('http');
const url = require('url');
class Application {
constructor() {
this.router = [];
}
get(path, fn) {
this.router.push({
path: path,
method: 'GET',
handle: fn
})
}
listen() {
http.createServer((req, res) => {
const { pathname } = url.parse(req.url);
for (const route of this.router) {
if (route.path === pathname) {
route.handle(req,res);
return;
}
if(route.path === '*'){
route.handle(req, res);
return;
}
}
}).listen(...arguments);
}
}
module.exports = Application;
MExpress_test.js
const MExpress = require('./MExpress');
const app = MExpress();
const fs = require('fs');
const path = require('path')
app.get('/index',(req,res)=>{
fs.readFile('./index.html', (err, data) => {
if (err) {
res.statusCode = 500;//服务器内部错误
res.end('500- Interval Serval Error!');
}
res.statusCode = 200;//设置状态码
res.setHeader('Content-Type','text/html');
res.end(data);
})
})
app.get('*',(req,res)=>{
res.setHeader('Content-Type', 'image/*');
fs.readFile(path.join(__dirname, req.url), function (err, data) {
if (err) {
throw err;
}
res.end(data);
})
})
app.listen(3001);