Node.js, JavaScript

Платформа Node.js

  • Javascript: миграция из браузера на сервер.
  • Google Chrome V8.
  • Быстрота и простота.
  • Наличие большого количества библиотек.

Javascript

  • Стандарт ECMA-262
  • Версии: ES1, ES2,..., ES6, ES2017(7), ..., ES2021 (12)
  • Обновления каждый год.
  • Javascript - реализация ECMAScript.
  • Другие реализации: JScript, ActionScript, QtScript.

Браузерные реализации Javascript

  • V8 — открытый исходный код, написан на C++, разработкой занимается Google.
  • Rhino — открытый исходный код, поддерживает Mozilla Foundation, написан на Java.
  • SpiderMonkey — это самый первый из появившихся JS-движков, который в прошлом применялся в браузере Netscape Navigator, а сегодня — в Firefox.
  • JavaScriptCore — ещё один движок с открытым кодом, известный как Nitro и разрабатываемый Apple для браузера Safari.

Браузерные реализации Javascript

  • Chakra (JScript9) — движок для Internet Explorer.
  • Chakra (JavaScript) — движок для Microsoft Edge.
  • Nashorn — движок с открытым кодом, являющийся частью OpenJDK, которым занимается Oracle.
  • JerryScript — легковесный движок для интернета вещей.

V8

  • Оптимизация встраивание кода (замена команды вызова функции на ее тело).
  • Скрытые классы (создаются во время выполнения, позволяют оптимизировать работу с прототипами).
  • Оптимизация: встроеный кэш вызовов.
  • Сборка мусора (mark-and-sweep - пометь и выброси).

V8. Компиляция в машинный код

  • full-codegen — простой и очень быстрый компилятор, который выдаёт сравнительно медленный машинный код.
  • Crankshaft — более сложный оптимизирующий JIT-компилятор, который генерирует хорошо оптимизированный код.
  • Несколько потоков.

V8. Компиляция в машинный код

  • Главный поток, который занимается тем, что от него можно ожидать: читает исходный JS-код, компилирует его и выполняет.
  • Поток компиляции, который занимается оптимизацией кода в то время, когда выполняется главный поток.
  • Поток профилировщика, который сообщает системе о том, в каких методах программа тратит больше всего времени, как результат, Crankshaft может эти методы оптимизировать.
  • Несколько потоков, которые поддерживают механизм сборки мусора.

V8. Компиляция в машинный код

  • Граф Hydrogen оптимизирован
  • Crankshaft переводит его в низкоуровневое представление, которое называется Lithium
  • Большинство реализаций Lithium зависимо от архитектуры системы.

Создание объектов: prototype

					
function Lang(code) {
    this.code = code;
   
    this.getCode = function() {
	return this.code;
    }
}

let ru = new Lang("ru");
console.log(ru.getCode());				    

let en = new Lang("en");
console.log(en.getCode());				    
					
function Lang(code) {
  this.code = code;
}

Lang.prototype.getCode = function(){
 return this.code;
}

let ru = new Lang("ru");
console.log(ru.getCode());				    
					

Создание объектов: class

					
class Lang {
    constructor(code) {
	this.code = code;
    }
    getCode() {
	return this.code;
    }
}

let ru = new Lang("ru");
console.log(ru.getCode());				    

let en = new Lang("en");
console.log(en.getCode());				    
					

LIFE (Immediately Invoked Function Expression)

(function () 
    {console.log("From function") })
();
					
  • Конструкция, позволяющая вызывать функцию непосредственно после ее определения.
  • Отделить логику и данные от "внешнего мира".
  • Сейчас (после ES6) не рекомендуется использовать.

ES6: let, const

if (foo) {
  let x = 5;
  setTimeout(function(){
    // тут x равен `5`
  }, 500);
}
// тут x равен `undefined`

for (let i = 0; i < 10; i++) {}
// `i` здесь не существует.
					
  • У let и const - блочная видимость.

Замыкания

function Lang(code) {  
    var displayCode = function(str) {
	console.log(str + ' ' + code);
    }
    return displayName;
}

var myFunc = Lang('ru');

myFunc('Code ');
myFunc('Your code ');					
					

Событийно-ориентированный подход

  • Традиционный подход: по умолчанию инструкция блокирующая.
  • Асинхронное программирование.
  • Передача функции обратного вызова (callback).

Запрос к сети на языке PHP

// Request to SMS gateway.
$client = new \GuzzleHttp\Client();
$data = array('login' => $login, 'psw' => $psw, 'fmp' => 2,
    'phones' => $phones, 'mes' => 'Вам сообщение:','charset' => 'utf-8');
$res = $client->request('GET', 'https://smsc.ru/sys/send.php', [
    'query' => $data
]);

Log::info((string)$res->getBody());
					

Запрос к сети на языке JavaScript

// Get html table with parameters.
$.post('/api/save_block_instance_data', $("#save_block_instance_form_" + biId).serializeObject(), function(result) {
    $("#save_block_instance_data_button_" + biId).button('reset');
    if (result.result == 'ok') {
        $.notify("Данные успешно сохранены!", "success");
    }
});
					

Пакетный менеджер

npm (Node Package Manager)
  • Web-ресурс https://www.npmjs.com/
    Поиск пакетов, документация для пакета, управление пакетами (публикация) и др.
  • Командная строка (CLI)
    Работа с проектом
  • База пакетов (registry)

Инициализация проекта

  • Через список вопросов npm init
  • Без списка вопросов npm init -y
  • Создается файл package.json
  • Секции package.json

    name, author, contributors, bugs, homepage, version, license, keywords, description, repository, main, private, scripts, dependencies, devDependencies, engines, browserslist

    Секция main

    Точка входа в проект

    					
    					    "main": "src/main.js"
    					
    					

    Секция scripts

    Скрипты, которые можно запускать

    
    "scripts": {
      "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
      "start": "npm run dev",
      "unit": "jest --config test/unit/jest.conf.js --coverage",
      "test": "npm run unit",
      "lint": "eslint --ext .js,.vue src test/unit",
      "build": "node build/build.js"
    }
    
    					
    npm run start

    Секция dependencies

    Список зависимостей, необходимых для выполнения проекта

    					
    "dependencies": {
      "vue": "^2.5.2"
    }
    					
    					

    Секция devDependencies

    Список зависимостей, необходимых для разработки проекта

    					
    "devDependencies": {
      "autoprefixer": "^7.1.2",
      "babel-core": "^6.22.1"
    }
    					
    					

    Указание версий

    • <major>.<minor>.<patch> - общая идеология
    • ~ - обновление только patch. Для ~0.13.1 до 0.13.2 обновится, а до 0.14.0 - нет.
    • ^ - обновление только minor и patch. Для ^0.13.1 обновится и до 0.13.2 и до 0.14.0.
    • * - обновление всех версий.
    • > - версия больше указанной.
    • >= - указанная версия или больше указанной.
    • <= - указанная версия или меньше указанной.
    • < - меньше указанной.
    • 1.0.0 || >=1.1.0 <1.2.0 - любые комбинации.
    • если ничего не указана, то применима только указанная.
    • latest - последняя выпущенная версия.

    Установка пакетов

    • Установить все из package.json
      npm install
    • Установить пакет package
      npm install package
    • Установить пакет package заданой версии
      npm install package@1.0.2

    Рекомендация: устанавливать пакет глобально, только если он предоставляет выполняемые команды, которые могут быть использованы для всех проектов.

    Установить глобально (необходимы права администратора):

    npm install package@1.0.2 -g

    Yarn VS NPM

    Претензии к NPM:
    • Скорость
    • Безопасность (позволяет запускать код при установке)
    Yarn - командный клиент для базы NPM.

    Платформа NodeJS

    • Событийная модель: концепция асинхроности.
    • Модульность
    • Работа с файловой системой
    • Ошибки

    Событийная модель: концепция асинхроности.

    • Один поток.
    • Класс EventEmitter.
    • Очередь событий, цикл событий.
    • Регистрация обработчика события.
    • Генерация события.
    Регистрация и генерация события
    				    
    const EventEmitter = require('events');
    
    class MyEmitter extends EventEmitter {}
    
    const myEmitter = new MyEmitter();
    myEmitter.on('event', () => {
        console.log('an event occurred!');
    });
    myEmitter.emit('event');
    				    
    				    
    Передача нескольких аргументов в событие
    				    
    const EventEmitter = require('events');
    
    class MyEmitter extends EventEmitter {}
    
    const myEmitter = new MyEmitter();
    myEmitter.on('event', (a, b) => {
        console.log('an event occurred:', a + b);
    });
    myEmitter.emit('event', 1, 3);
    				    
    				    
    Синхронное и асинхронное
    Все обработчики выполняются синхронно (по мере регистрации).
    				    
    setTimeout(callback, 0)
    process.nextTick(callback)
    				    
    				    
    Модульность
    				    
    // Импорт локального модуля:
    const myLocalModule = require('./path/myLocalModule');
    
    // Импорт JSON файла
    const jsonData = require('./path/filename.json');
    
    // Импорт из node_modules или встроенного в Node.js модуля:
    const crypto = require('crypto');
    				    
    				    
    				    
    				    
    // Модуль.
    module.exports = class Square {
      constructor(width) {
        this.width = width;
      }
    
      area() {
        return this.width ** 2;
      }
    };
    				    
    				    
    Работы с файловой системой
    				    
    // Асинхронная обработка.
    const fs = require('fs');
    
    fs.unlink('/tmp/hello', (err) => {
      if (err) throw err;
      console.log('successfully deleted /tmp/hello');
    });
    				    
    				    
    				    
    				    
    // Синхронная обработка.
    const fs = require('fs');
    
    try {
      fs.unlinkSync('/tmp/hello');
      console.log('successfully deleted /tmp/hello');
    } catch (err) {
      // handle the error
    }
    				    
    				    
    				    
    • Абсолютный путь.
    • Относительный путь.
    • URL.
    				    
    fs.readFileSync('/tmp/hello');				    
    fs.readFileSync('../hello');				    
    fs.readFileSync(new URL('file:///tmp/hello'));				    
    				    
    				    
    Работа с ошибками
    				    
    const fs = require('fs');
    fs.unlinkSync('/tmp/hello');
    				    
    				    
    				    
    				    
    try {
        fs.unlinkSync('./hello');
        console.log('successfully deleted /tmp/hello');
    } catch (err) {
      // handle the error
      console.log('File not deleted');
    }
    
    				    
    				    
    Класс Error
    				    
    const EventEmitter = require('events');
    const ee = new EventEmitter();
    
    setImmediate(() => {
      // This will crash the process because no 'error' event
      // handler has been added.
      ee.emit('error', new Error('This will crash'));
    });