Translate

Поиск по этому блогу

суббота, 29 сентября 2018 г.

Основы Node JS ( I ).

Основы работы с Node JS. Часть - 1.

Node.js — это среда выполнения JavaScript, построенная на JavaScript-движке V8 из Chrome. В основе Node.js лежит событийно-управляемая модель с неблокирующими операциями I/O, что делает её легкой и эффективной.



Все материалы по JavaScript


Другими словами: Node.js предлагает вам возможность писать невероятно производительный серверный код с использованием JavaScript. Как говорится в официальном описании: Node.js — это среда выполнения, использующая тот же JavaScript-движок V8, который вы можете найти в браузере Google Chrome.

Функции

  1. Простая:


  2. 
    function hello(){
     console.log('Hello Proger');
    };
    
    hello();
    
    


  3. Именованная:


  4. var someName = function(){
     console.log("SomeName Function");
    };
    someName();
    
    


  5. Функция из функции:


  6. 
    function call(func){
     func();
    };
    
    call(someName);
    
    


Модули

В файл array.js запишем:


let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};

console.log( array_counter( [ 1, 33, 45, 23, 7, 31, 40 ] ) );

Подключение к index.js

require('./array');



Если мы подключаем какой-то файл, то это не значит, что мы можем использовать все функции из этого файла.

Например, если вывод в консоль перенести из файла array.js в index.js, то получим ошибку.

Если из файла нужно что-то просто вывести, то достаточно подключить, как в примере выше. а если использовать функции вне модуля, нам нужно их экспортировать.

  1. Используется метод modelr.exports = name_function;
  2. Директиве require('./array'); присвоить переменную.
Файл index.js


let counter = require('./array');

console.log( counter( [ 1, 33, 45, 23, 7, 31, 40 ] ) );



Файл array.js


let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};

module.exports = array_counter;



Несколько функций из одного модуля.


let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};


let some_value = 324;

let multiplay = function(x, y){
 return `Число ${x} умножить на ${y} = ${x * y} `;
};

module.exports.array_counter = array_counter;
module.exports.some_value = some_value;
module.exports.multiplay = multiplay;



Файл index.js


let things = require('./things.js');

console.log( things.array_counter( [ 1, 33, 45, 23, 7, 31, 40 ] ) );

console.log(things.some_value);

console.log(things.multiplay(4, 8));



Упростим


module.exports.array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};


module.exports.some_value = 324;

module.exports.multiplay = function(x, y){
 return `Число ${x} умножить на ${y} = ${x * y} `;
};




let array_counter = function ( array ) {
 return 'В массиве находится ' + array.length + ' элементов.';
};


let some_value = 324;

let multiplay = function(x, y){
 return `Число ${x} умножить на ${y} = ${x * y} `;
};

module.exports = {
array_counter : array_counter,
some_value : some_value,
multiplay : multiplay
};





Отслеживание событий в Node

Подключение встроенных модулей.

Все делается через директиву require('name_modele');

let events = require('events');

Теперь есть подключенный модуль, который отслеживает различные события.

Создадим функцию, которая отслеживает конкретное событие. Её мы и будем вызывать, чтобы убедиться, что событие сработало. Это пример чисто технический. Сами создаем событие и сами его отслеживаем.

Создадим переменную, которая будет отвечать за обработчик события.

let myEmit = new events.EventEmitter();

Для события используем метод .on(). Первым аргументом - название события, которое отслеживаем. Вторым аргументом запишем функцию. которая будет срабатывать на это событие.

Например:

myEvent.on('click', function(){console.log('Event click'});

Теперь остается только вызвать придуманное нами событие и передать параметр text.


let events = require('events');

let myEmit = new events.EventEmitter();

myEmit.on('some_event', function(text){
 console.log(text);
});

myEmit.emit('some_event', 'Обработчик событй сработал');





Модуль позволяющий наследовать события - Util

  1. Создали переменную в которую присвоили модуль util.
  2. Создадим конструктор.
  3. После этого можно использовать модуль util, чтобы все объекты созданные на основе этого конструктора Cars унаследовали обработчик событий.


util.inherits(ctor, superCtor);

Первым параметром указываем конструктор, который будет наследовать. Вторым - что конкретно наследовать.

util.inherits(Cars, events.EventEmitter);

Круглые скобки событию не надо.

Теперь мы можем создавать различные объекты, которые будут сразу наследовать обработчик событий.


let events = require('events');
let util = require('util');

let Cars = function(model){
 this.model = model;
}

util.inherits(Cars, events.EventEmitter);

let bmv = new Cars('BMW');
let audi = new Cars('Audi');
let volvo = new Cars('Volvo');



На самом деле util.inherits просто позволяет наследовать прототипы от одного конструктора к другому (не только конструктор событий).

Посмотрим на практике:

  1. Создадим массив cars, в который пометим все объекты, которые мы создали.


  2. let cars = [bmv, audi, volvo];

  3. Теперь ы легко можем перебирать массив и объекты в нем.


  4. cars.forEach(function(car){ car.on('speed', function(text){ console.log( `Auto ${car.model} speed is $(text}`)); }); });

  5. Вызываем события.


bmw.emit('speed', '245.3 km');

Код полностью index.js


let events = require('events');
let util = require('util');

let Cars = function(model){
 this.model = model;
}

util.inherits(Cars, events.EventEmitter);

let bmw = new Cars('BMW');
let audi = new Cars('Audi');
let volvo = new Cars('Volvo');

let cars = [bmw, audi, volvo];

cars.forEach(function(car){
 car.on('speed', function(text){
  console.log( 'Auto ' + car.model + ' speed is ' + text);
 });
});

bmw.emit('speed', '245.3 km');






Теперь мы можем добавить различные авто и получить у каждого событие.


bmw.emit('speed', '245.3 km');
volvo.emit('speed', '198 km');
audi.emit('speed', '259 km');





Запись и чтение файлов

Синхронное чтение.

Создадим text.txt файл из которого будем что-то читать.

Добавим в него текст:

Файл text.txt.


Ура! Вы меня прочитали!
You read this text.



При этом важно указать кодировку, иначе кириллицу отображать не будет.



Читать и записывать файлы поможет модуль fs. Вызываем его.

fs.readFileSync(path, options);

Первый параметр - файл и путь к нему.

Второй - кодировка. В нашем случае - 'utf8'

Пока не прочитаем файл, код ниже не сработает.

Поместим весь этот текст в переменную file_readed


let fs = require('fs');

let file_read = fs.readFileSync('text.txt', 'utf8');

console.log(file_read);





Синхронная запись.

Используем тот же модуль, но функцию

fs.writeFileSync(path, data, options);

Первый параметр - название файла куда записывать. Если его нет, то он будет создан.Например some_new_file.txt

Второй параметр - данные (текст). Можно указать просто имя переменной, в которой этот текст.

Например:

let message = 'Hello World - Привет Мир\n' + file_read;


let fs = require('fs');

let file_read = fs.readFileSync('text.txt', 'utf8');

let message = "Hello World -  Привет Мир \r\n" + file_read;

fs.writeFileSync('some_new_file.txt', message);



Запустим

node index


Ничего не произойдет в консоли, но зато появится новый файл some_new_file.txt в нашей директории.

Откроем и там:



Асинхронная.

Отличается тем, что код, который расположен ниже функции будет обрабатываться и не ждать завершения обработки функций чтения и записи.

Чтение файлов асинхронное

Функция почти такая же. но есть третий параметр, который есть функция которая сработает тогда. когда файл будет прочтен.

В этой функции первым параметром err - ошибка. Если не получится прочитать файл обратимся к ней, а вторым data - непосредственно данные.


let fs = require('fs');

fs.readFile('text.txt', 'utf8', function(err, data){
 console.log(data);
});

console.log('Test');



Вывод слова Test для наглядности асинхронности кода.



Запись файла асинхронная

Используется почти такая же конструкция, что и для чтения.

Вторым параметром пойдет тот текст, который мы хотим записать. Можно его поместить в переменную, как и с синхронными функциями.

Третьим параметром функция в которой можно ничего не возвращать.


let fs = require('fs');

fs.readFile('text.txt', 'utf8', function(err, data){
 console.log(data);
});

fs.writeFile('some.txt', 'Hello Programmers from me', function(err, data){});

console.log('Test');





Удаление файлов. Создание и удаление директории.

Удаление файлов.

Используется модуль fs

let fs = require('fs');

fs.unlinkSync(path);
fs.unlink(path, callback);


Первый параметр название файла который удаляем, или путь.

Второй - Функция, которая будет срабатывать, после завершения удаления конкретного файла.

В нее можно ничего не передавать, но она нужна, чтобы не было ошибки.


let fs = require('fs');

fs.unlink('text1.txt', function(){
 console.log('File text1 deleted');
});





Создание директории.


fs.mkdirSync(path, mode);
fs.mkdir(path, mode, callback);


Первый параметр - путь (название папки)

Второй - не обязательный при синхроне.


let fs = require('fs');

fs.mkdir('new-test', function(){
 fs.writeFile('./new-test/some-new.txt', 'Hello world!', function(){
  console.log('everything is done');
 });
});





Удаление.

Удалить можно только пустую папку.

fs.rmdirSync(path);
fs.rmdir(path, callback);



let fs = require('fs');

fs.unlink('./new-test/some-new.txt', function(){
  fs.rmdir('./new-test', function(){
  console.log('Удалили  файл и папку');
 });
});









                                                                                                                                                             

пятница, 28 сентября 2018 г.

ES6: Символы (symbols) (XV).

Symbol

Перед тем. как перейти к подробному изучению нового типа данных в ES6, стоит разобраться зачем они нужны.

Symbol - специальный тип данных с помощью которого можно создать уникальный идентификатор свойств объектов. Именно для этого и придумали символы.



Все материалы по ES6


Символы - уникальные и неизменные значения.

Символы позволяют разработчикам добавлять новые идентификаторы или свойствам объектов, при этом не резервируя строковые названия для этих свойств.

В основном символы используются внутри языка JavaScript и вам вряд ли придется часто с ними работать.

Давайте перейдем в редактор и посмотрим как создаются и используются символы.

Символы поддерживаются всеми современными браузерами и последними версиями ноды. Для поддержки старых версий на сайте Babel

Пройти по пути сайт Babel -> Usage ->Polyfill



Установить через npm в папку проекта и подключить в файле index.html

<script src="node_modules/babel-polyfill/dist/polyfill.min.js"></script>

Откроем в редакторе файл symbol.js, подключим его к нашему файлу index.html, точно так же, как мы это делали в предыдущих частях руководства.

<script src="src/symbol.js"></script>

Создание символов

Создадим переменную и в нее пометим результат вызова функции Symbol.

Результат выведем в консоль.


let symbol = Symbol();

console.log(symbol);



Посмотрим в консоль



Давайте посмотрим на тип переменной symbol используя оператор typeof.


let symbol = Symbol();

console.log( typeof symbol);





Заметьте, что при создании нового символа мы не используем слово new.

Если мы, все таки попробуем, то получим ошибку.


let symbol = new Symbol();

console.log( typeof symbol);





Это происходит потому, что Symbol не является конструктором.

У функции Symbol() есть необязательный аргумент, с помощью которого мы можем указать имя символа, что может быть полезно при отладке.


let symbol = Symbol('name');

console.log(symbol);





Давайте попробуем создать еще один символ и присвоить ему такое же имя и посмотрим, будет ли равняться один другому.


let symbol = Symbol('name');
let symbol2 = Symbol('name');

console.log(symbol);
console.log(symbol2);





При создании символов мы увидели одинаковые сообщения. но при этом символы не равны!

Каждый символ уникален. Это можно представить так. что внутри символа хранится некий уникальный код.

Таким образом имя символа мы используем для обращения к нему.

Создать два одинаковых символа нельзя!

Посмотреть на внутренние значения символа нам тоже не удастся.

Еще одним методом создания символов является метод Symbol.for.


let symbol = Symbol.for('name');

console.log(symbol);



В консоли получим тоже сообщение. что и при первом методе создания символа.



Отличие между двумя способами заключается в том, что если создать еще один сивол методом for и указать тоже самое имя, то мы получим равные символы.


let symbol = Symbol.for('name');
let symbol2 = Symbol.for('name');

console.log(symbol === symbol2);



В консоли получим значение: true.

Первый и второй символы - это один и тот же символ.

Когда мы используем метод for, то он вначале попробует найти символ по имени и если ему это не удастся, то он создаст новый символ.

Благодаря методу for, символ можно получить из любого места в программе, так как они заносятся в так называемый глобальный реестр.

Символы, созданные функцией Symbol не попадают в этот реестр и их нельзя найти с помощью метода for.

Имя символа можно получить методом keyFor.


let symbol = Symbol.for('name');
let name = Symbol.keyFor(symbol);

console.log(name);




В консоли мы увидим - name.

Если в метод .for не передать имя, то получим ошибку

let symbol = Symbol.for();

Будет ошибка!

Использование символов.

В ES5 свойства объектов должны быть строками.

В ES6 они могут быть строками и символами.

Создадим объекта и в качестве второго свойства присвоим символ.


let user = {
 name : 'John',
 [Symbol('password')] : 'r89n123'
};

console.log(user.password);



Вызов функции символа мы не можем использовать в качестве названия свойства, поэтому нам его необходимо было обернуть в квадратные скобки [].

В консоли мы увидим undefined.

Попробуем посмотреть на все свойства объекта -


let user = {
 name : 'John',
 [Symbol('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));



Мы увидим только name.



Попробуем еще и

console.log(Object.getOwnPropertyNames(user));



Как же получить доступ к паролю?

Давайте попробуем использовать метод .for().


let user = {
 name : 'John',
 [Symbol('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);



И в консоли опять - undefined.



Если мы создаем символ с помощью функции Symbol(), то он не попадает в глобальный реестр и мы не сможем его найти с помощью метода .for()


выше приведено доказательство этому.

Но если у объекта указать с .for()


let user = {
 name : 'John',
 [Symbol.for('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);





В ES6 был добавлен метод, который позволяет посмотреть символы у объектов.

Этот метод находится у объектов Object и называется getOwnPropertySymbols


let user = {
 name : 'John',
 [Symbol.for('password')] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);

console.log(Object.getOwnPropertySymbols(user));





Даже если мы уберем .for у объекта, то все равно мы увидим тоже самое сообщение.



А если убрать и имя, то


let user = {
 name : 'John',
 [Symbol()] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

let password = user[Symbol.for('password')];

console.log(password);

console.log(Object.getOwnPropertySymbols(user));



То мы все равно узнаем, что у объекта есть символ, но какое именно мы не знаем и никак получить к нему доступ мы не можем!



Для того, чтобы это исправить мы создадим отдельную переменную password.


let password = Symbol();

let user = {
 name : 'John',
 [password] : 'r89n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

// let password = user[Symbol.for('password')];

// console.log(password);

console.log(Object.getOwnPropertySymbols(user));





Результат будет тот же, но теперь символ хранится в переменной.

Смволы были добавлены в язык не для того, чтобы что-то спрятать. Они были добавлены для того, чтобы избежать конфликта имен свойств.

Так мы можем добавить нашему объекту еще одно свойство password.


let password = Symbol();

let user = {
 name : 'John',
 [password] : 'r89n123',
 password: 'a9b9c9n123'
};

console.log(user.password);

console.log(Object.keys(user));

console.log(Object.getOwnPropertyNames(user));

// let password = user[Symbol.for('password')];

// console.log(password);

console.log(Object.getOwnPropertySymbols(user));



В консоли:



При этом прямого доступа к символу нет, но это не значит, что его нет вообще.

При желании мы можем его получить.

Как я и говорил, нам как пользователям языка, нет необходимости создавать свои собственные символы, но в ES6 есть множество встроенных символов.

Эти символы называют - Well-known symbols или хорошо известные символы.

Одним из них является Symbol.iterator. Благодаря этому символу мы можем получить доступ к внутреннему методу объекта.

Выглядит это так:

У объекта должно быть свойство Symbol.iterator. Это свойство является методом, поэтому - круглые скобки и фигурные скобки .

Теперь мы можем добавить объекту свойство iterator и никакого конфликта не будет.


let object = {
 iterator: 0,
 [Symbol.iterator](){}
}



Этот метод, который мы определили, используется конструкцией forof благодаря которой мы можем перебирать или итерировать (отсюда и название символа) объект, у которого определен этот специальный метод.

Об этом мы поговорим уже в следующем посте.





                                                                                                                                                             

четверг, 27 сентября 2018 г.

ES6: Создание обещаний (promises)(XIV-2).

Создание обещаний (promises).

В качестве примера, мы продолжим рассмотрение процесса получения визы.



Все материалы по ES6


ES6 для начинающих (2)

В редакторе откроем новый файл- promises.js. Подключим его в нашем файле

index.html

<script src="src/promises.js"><script>

В этом файле создадим функцию.


function applyForVisa( document ) {
    console.log('Обработка заявления... ');
};

applyForVisa({});



Она называется applyForVisa(). Это функция принимает документы на визу.

В консоли браузера мы выведем - Обработка заявления... . После чего мы в эту функцию вызываем. и в качестве объекта документа отправляем пустой объект - applyForVisa({});

Процесс получения визы займет всего 2 секунды. Эту задержку стимулируем с помощью метода setTimeout ();.

Он принимает функцию и количество миллисекунд.

А что именно произойдет через эти две секунды, мы напишем функции.

Создадим переменную виза. В качестве значения присвоим - пустой объект let visa = {};.

А вот что делать дальше?


function applyForVisa( document ) {
    console.log('Обработка заявления... ');
    setTimeout( function () {
        let visa = {};
       // ??
    }, 2000);
};

applyForVisa({});



Допустим визы мы получили. Как нам передать и обратно?

Если мы напишем return visa; то мы вернем его из функции которые отправляем в

setTimeout, но при этом пользователь визу не получил!

Таким образом вернуть визу мы не можем!

Для решения этой проблемы мы можем использовать функцию обратного вызова, которая определим при подаче документов.


applyForVisa({},function( visa ) {
	console.info('Виза получена!');
});



Данная функция получит visa, в качестве параметра. И в консоль браузера мы выедем сообщение - "Виза получена!".

Для вывода в консоль мы будем использовать метод - console.info();.

Теперь функция applyForVisa принимает не только документы ,но и функцию.

Назовем её resolve - то есть разрешить. После того как, мы создали объект виза, вызовем функцию resolve и в качестве аргумента отправим объект visa.


function applyForVisa( document, resolve ) {
    console.log('Обработка заявления... ');
    setTimeout( function () {
        let visa = {};
        resolve( visa );
    }, 2000);
};

applyForVisa( {}, function ( visa ) {
    console.info('Виза получена!');
});



Давайте посмотрим что у нас получилось в консоли.



Мы увидим сообщение- Обработка заявления и через 2 секунды, мы видим сообщение Виза получена.

На данный момент мы отправляем функцию обратного вызова на случай если визу нам одобряют. Если нам её не одобряют, то давайте отправим еще одну функцию обратного вызова.

Данная функция в качестве параметра примет причину - reson, почему нам отказали в визе. Давайте выведем эту причину в консоле браузера Используя метод console/error( reson )

Теперь функция applyForVisa принимает документы, функцию на случай если Виза одобряется, и функцию на случай если в визе отказывают. Назовем эту функцию reject - отказать.

Теперь, давайте немного изменим логику и в 50% случаев будем визу одобрять, a в 50% отказывать.

Для этого воспользуемся Math.random();, чтобы получить случайное число. Если это число будет больше 0,5 то мы вызовем функцию resolve в качестве аргумента отправим пустой объект.

Представим, что это будет виза. В противном случае мы вызовем функцию reject и в качестве аргумента напишем - "В визе отказано: не хватило документов...".

Вызов функции resolve( visa ); мы уберем. Кстати, заметьте, функцию resolve я могу вызывать столько раз сколько я хочу.

Функцию reject я могу звать столько раз сколько я захочу и это может быть очень серьезной проблемой, если я использую какую-то стороннюю библиотеку, потому что этим кодом Я не руковожу!

Решить эту проблему нам помогут обещания! Но об этом чуть позже.


function applyForVisa( document, resolve, reject ) {
    console.log('Обработка заявления... ');
    setTimeout( function () {
        Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
       
    }, 2000);
};

applyForVisa( {}, function ( visa ) {
    console.info('Виза получена!');
},
function ( reson ) {
    console.error( reson );
});



Давайте посмотрим что у нас получилось в консоли.

При перезагрузке страницы мы будем получать два вида сообщений:



Добавим еще две функции.

Первая будет называться bookHotel() - с помощью которой мы сможем зарезервировать номер в отеле, а вторая будет называться buyTickets() - с помощью которой мы сможем купить билеты на самолет.

Логика у них будет очень похоже на функцию applyForVisa. Поэтому просто оставим их пустыми.

После того, как мы получили визу, давайте вызовем функцию bookHotel и допустим что отелю или компании которая занимается бронированием отелей, необходимо отправить визу.

Благо, что мы её уже получили и поэтому можем отправить.

Далее, нам необходимо отправить ещё одну функция обратного вызова на случай если отель нам зарезервировали.

в качестве аргумента отправим reservation. И давайте отправим функцию на случае ошибки.

Ой какой читабельный код получается!!!

На случай Если всё хорошо, и мы зарезервировали номер в отеле, давайте купим билеты.

Для покупки билета нам тоже нужно отправить номер резервации.

И наподобие кода выше: функцию на случае успеха и функцию на случай неудачи.

Если всё правильно записать, то получится достаточно много кода.

Это и есть как раз то, что называют Callback Hell.


function applyForVisa( document, resolve, reject ) {
    console.log('Обработка заявления... ');
    setTimeout( function () {
        Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
       
    }, 2000);
};
function bookHotel () {};

function buyTickets () {};

applyVisa({}, function( visa ){
	console.info('Виза получена!');
	bookHotel( visa, function (reservation){
		buyTikkets(reservation, function () {}, function () {});
	}, function (error) {})
},
function( reson ) {
	console.error( reson );

});



Красным отмечен полный кошмар вложений из функций обратного вызова. Их может быть очень очень много и это сделает код полностью нечитабельным!

Callback Hell - когда у одной функции обратного вызова есть еще функция обратного вызова и у той тоже функция обратного вызова, и так далее.

Таким образом есть две проблемы.
  1. - функции resolve reject могут быть вызваны один, два или три раза, а могут быть не вызваны ниразу. Мы предполагаем, что они будут вызваны один раз, но гарантировать это мы не можем.
  2. - это нечетабельный Callback Hell .
Всё это мы ррешим с помощью обещаний.


function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           
        }, 2000);
        
    });
    return promise;
};

function bookHotel () {};

function buyTickets () {};

applyForVisa({})
    .then(
            function ( visa ) {
            console.info('Виза получена!');
            bookHotel();
            },
            function ( reson ) {
            console.error( reson );
         });



Код должен работать также.

В консоли мы увидим такие же сообщения при перезагрузке страницы.

Перепишем с использованием стрелочных функций:


function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           
        }, 2000);
        
    });
    return promise;
};

function bookHotel () {};

function buyTickets () {};

applyForVisa({})
    .then( visa => console.info('Виза получена!'),
          reson => console.error( reson ));



Для того, чтобы запланировать последующие действия, мы также можем использовать метод .then().

На случай, если обещание будет выполнено нам надо отправить туда одну функцию.

Таким способом мы отправим туда функцию бронирования отеля - boorHotel() и вместо того, чтобы на каждом этапе определять функцию на случай ошибки, мы можем определить одну для всей операции в целом.

Если на каком-то этапе произойдет ошибка, то сработает та функция которую мы сейчас определим.

Для этого, после .then(bookHotel мы сделаем еще один метод . Туда отправим buyTickets, а далее - используя метод .catch у обещания, мы выведем ошибку, которая нам будет передана. При этом, обработчик ошибки у первого метода мы можем убрать!

И для проверки в функцию bookHotel добавим вывод сообщения в консоль - Бронируем отель.


function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           
        }, 2000);
        
    })
    return promise;
}

function bookHotel () {
    console.log('Бронируем отель.')
};

function buyTickets () {};

applyForVisa({})
    .then( visa => console.info('Виза получена!'))
    .then( bookHotel )
    .then( buyTickets )
    .catch( error => console.error( error ));



В результате в консоли мы увидим, что при одобрении визы у нас появится пункт - Бронируем отель.



А если виза не одобрена, то вывод как и в предыдущих случаях .

Можно добавить Покупаем билеты в buyTickets



При отказе в визе мы сразу будем попадать в функцию, которую отправили в метод .catch.

Сейчас мы видим 3 сообщения - виза получена, бронируем отель и покупаем билеты.

Заметьте метод .then мы используем три раза.



Мы используем одно обещание или несколько?

Как минимум одно обещание в методе applyForVisa мы создаем. Далее, мы его возвращаем.

Используем метод .then выводим сообщение в консоль браузера.

Далее, мы используем .then( bookHotel ).

Это одно и то же обещание или нет?

Обещание выполняется или не выполняется только один раз!

То есть обещание может находиться только в одном из состояний.
  1. Оно может быть Panding - Ожидание.
  2. Оно может быть resolved - Выполнена
  3. или rejected - Отказано или не выполнено.
То есть, если я выполнил обещание используя метод resolved, состояние этого обещания я уже не могу поменять на rejected, используя метод reject. Все последующие попытки изменить состояние обещания будут игнорироваться.

Это легко проверить если после Math.random() обещание ещё раз выполним, а потом отменим а потом выполним.


function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           resolve();
           reject();
           resolve();
        }, 2000);
        
    })
    return promise;
}

function bookHotel () {
    console.log('Бронируем отель.');
};

function buyTickets () {
    console.log('Покупаем билеты.');
};

applyForVisa({})
    .then( visa => console.info('Виза получена!'))
    .then( bookHotel )
    .then( buyTickets )
    .catch( error => console.error( error ));
    


Давайте посмотрим что у нас будет в браузере.

Заметьте, мы получили не 6 сообщений или 9, все те же 3.

То есть обещание было выполнено один раз.

Тоже самое с ошибкой. Мы получили только одно сообщение об ошибке.

Для того чтобы иметь возможность использовать методы .then по цепочке, нам необходимо каждый раз создавать и возвращать новое обещание!

Благо, это делает автоматически!

То есть, вот здесь (на фото ниже показано стрелкой), после того как выполняется console.info('Виза получена!')), создается новое обещание, которое передается дальше!



Дальше, новому обещания мы присылаем функцию bookHotel, на случай если оно будет выполнено.

Если мы попадаем функцию bookHotel ,после того как мы выводим сообщение 'Бронируем отель.' создается новое обещание и передается дальше.

Дальше мы увидим сообщение - Покупаем билеты - создаются новые обещания и отправляется дальше.

Новое обещание мы можем использовать а можем не использовать.

Более того, после метода .catch();, мы можем использовать еще раз .then().


function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           resolve();
           reject();
           resolve();
        }, 2000);
        
    })
    return promise;
}

function bookHotel () {
    console.log('Бронируем отель.');
};

function buyTickets () {
    console.log('Покупаем билеты.');
};

applyForVisa({})
    .then( visa => console.info('Виза получена!'))
    .then( bookHotel )
    .then( buyTickets )
    .catch( error => console.error( error ))
    .then(() => console.log('Я всё еще тут.'));



И это сообщение мы увидим в любом случае!

Для того чтобы забронировать отель, нам необходимо предоставить визу, поэтому функция bookHotel () будет принимать в качестве параметра visa.

и для того чтобы нам не отказывали в визе, можно поставить 0 в условном выражении Math.random() > 0 ? .

Давайте посмотрим и мы видим что визу у нас undefined.



Давайте разберемся почему?

Как я уже сказал, когда мы используем .then(), каждый раз создается новое обещание.

Так вот, обещание в котором мы отправляем функцию bookHotel () ничего про объект visa не знает. Для этого нам необходимо объект visa из первого обещания вернуть.

Для этого нам необходимо поставить фигурные скобки после сообщения виза получена и вернуть визу.



function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           resolve();
           reject();
           resolve();
        }, 2000);
        
    })
    return promise;
}

function bookHotel ( visa ) {
    console.log('Бронируем отель.');
    console.log('visa =' + visa);
};

function buyTickets () {
    console.log('Покупаем билеты.');
};

applyForVisa({})
    .then( visa => {
        console.info('Виза получена!');
        return visa; 
    })
    .then( bookHotel )
    .then( buyTickets )
    .catch( error => console.error( error ));
    



Давайте правильно что получилось .



И теперь мы видим visa =[object Object]. То есть нам удалось передать visa из одного обещания в другое.

Создадим функцию получения визы и в нее поместим код:


function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           resolve();
           reject();
           resolve();
        }, 2000);
        
    })
    return promise;
}
function getVisa ( visa ) {
    console.info('Виза получена!');
    return visa; 
}

function bookHotel ( visa ) {
    console.log('Бронируем отель.');
    console.log('visa =' + visa);
};

function buyTickets () {
    console.log('Покупаем билеты.');
};

applyForVisa({})
    .then( getVisa ) 
    .then( bookHotel )
    .then( buyTickets )
    .catch( error => console.error( error ));
    


При проверке получим тот же самый результат.

Если для покупки билета, нам необходимо передать информацию о забронированном отеле, то для этого из функции bookHotel нам нужно вернуть что-то. Давайте вернем пустой объект.

Далее в функции buyTickets мы принимаем параметр booking - так назвали его. И посмотрим на него в консоли.

function buyTickets ( booking ) {
    console.log('Покупаем билеты.');
    console.log('Бронь', booking);
};


И в консоли мы увидим объект Бронь.



Давайте полагаться на JavaScript не будем и с функции getVisa() сами вернём обещание.

В теле просто вызовем resolve( visa ) с параметром - visa.


function getVisa ( visa ) {
    console.info('Виза получена!');
    return new Peomise( function ( resolve, reject ) {
        resolve();
    }); 
}

В консоли мы получим тот же самый результат. Тоже самое сделаем в функции bookHotel Для разнообразия в нее передадим функцию reject('Нет мест!');

function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > .5 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           resolve();
           reject();
           resolve();
        }, 2000);
        
    })
    return promise;
}
function getVisa ( visa ) {
    console.info('Виза получена!');
    return new Promise( function ( resolve, reject ) {
        resolve();
    }); 
}

function bookHotel ( visa ) {
    console.log('Бронируем отель.');
    console.log('visa =' + visa);
    return new Promise ( function (resolve, reject ) {
        reject('Нет мест!');
    });
};

function buyTickets ( booking ) {
    console.log('Покупаем билеты.');
    console.log('Бронь', booking);
};

applyForVisa({})
    .then( getVisa ) 
    .then( bookHotel )
    .then( buyTickets )
    .catch( error => console.error( error ));
    



В консоли увидим.



До функции -купить билеты мы не дошли.

Если поменять reject('Нет мест!') на resolve({}), то мы пройдем через все функции.

То есть и получим визу и отель и билеты...

В функциях getVisa bookHotel мы сразу выполняем обещания. И если это так, то нет необходимости использовать конструктор.

Например так:


function bookHotel ( visa ) {
    console.log('Бронируем отель.');
    console.log('visa =' + visa);
    return Promise.resolve( visa );
};



Если мы хотим сразу отклонить обещание, то можно сделать сразу reject так - return Promise.reject( 'Some Text' );

В данном случае мы моментально отклоняем обещание.

В функции getVisa мы используем конструктор, но в теле функции мы сразу выполняем обещание.

Давайте это исправим и превратим эту функцию в асинхронную.

для этого воспользуемся методом setTimeout и стрелочной функцией, которой вызовем resolve(visa) и подождем 2 сек.

Таким образом все процедура должна занять 4 сек.


function applyForVisa( documents ) {
    console.log('Обработка заявления... ');
    let promise = new Promise( function ( resolve, reject ) {
        setTimeout( function () {
            Math.random() > 0 ? resolve ({}) : reject ('В визе отказано: не хватило документов...')
           resolve();
           reject();
           resolve();
        }, 2000);
        
    })
    return promise;
}
function getVisa ( visa ) {
    console.info('Виза получена!');
    return new Promise( function ( resolve, reject ) {
        setTimeout( () => resolve( visa ), 2000);
    }); 
}

function bookHotel ( visa ) {
    console.log('Бронируем отель.');
    console.log('visa =' + visa);
    return Promise.resolve( visa );
};

function buyTickets ( booking ) {
    console.log('Покупаем билеты.');
    console.log('Бронь', booking);
};

applyForVisa({})
    .then( getVisa ) 
    .then( bookHotel )
    .then( buyTickets )
    .catch( error => console.error( error ));
    


Теперь будут последовательно, через 2 сек появляться сообщения.

Первое - Обработка заявления...
2 сек
Виза получена! и через 2 сек все остальное.

Думаю, что вам стало более понятно, как работают обещания.

Далее мы рассмотрим применение обещаний и как работать с несколькими обещаниями одновременно.





                                                                                                                                                             

среда, 26 сентября 2018 г.

ES6: Обещания - Promise (XIV-1).

Обещания - Promise

Сегодня мы рассмотрим обещания в ES6 или как они называются по-английски Promise.



Все материалы по ES6


ES6 для начинающих (2)

До ES6 для работы с обещаниями нам приходилось использовать различные библиотеки, но теперь обещание поддерживается во всех современных браузерах.

Давайте разберемся Зачем вообще нужны эти обещания?

Очень часто мы хотим сделать чтобы что-то произошло после того, как произойдет что-то другое.

Допустим, мы кликаем на кнопку и появляется сообщение.

Традиционно, для реализации такого рода взаимодействия, используется функция обратного вызова (callbacks). Если вы когда-нибудь писали функцию которую должна сработать при нажатии на кнопку, то вы знаете что такое функция обратного вызова.



Помимо работы с событиями DOM, функция обратного вызова также используется для общения с сервером посредством ajax.

Допустим мы хотим подгрузить данные сервера.Как только мы их получим, нам нужно сначала их обработать. Далее данные необходимо проверить и только потом отобразить.

При этом мы не хотим сидеть и ждать, когда все эти операции закончится.

Приложение должно работать дальше. Если использовать функции обратного вызова для каждой из этих операций то код может превратиться в так называемый callback hell - когда у функции обратного вызова есть своя функция обратного вызова, у которой есть своя функция обратного вызова и вы вbдите как всё это выглядит.



Для маленьких приложений это не такая большая проблема, но для больших всё это может превратится в очень большую головную боль, особенно при отладке.

Если бы мы использовали обещания, то код выглядел бы следующим образом:



Заметьте насколько он компактен и легко читается.

Давайте наглядно посмотрим как работают обещание.

Допустим вы хотите поехать отдыхать в другую сторону.

Для этого вам необходимо:
  1. - сначала получить визу
  2. - забронировать номер в отеле,
  3. - и в конце купить билет на самолет.


Все эти действия aсинхронны. Это означает, что при подаче документов мы не будем сидеть и ждать результата. Мы пойдём заниматься дальше своими делами.

Сначала вы заполняете документы и отправлять их в посольство.

От посольства вы получаете обещание, что они дадут вам знать получили вы визу или нет.

Пока обещание выполняется оно находится в состоянии Pending ( ожидание ). Далее обещание может быть сдержанным, в таком случае она будет в состоянии Resolved, или несдержанно. В таком случае мы получим ошибку Error и обещание будет находиться в состоянии Rejected.



В зависимости от результата, вы можете спланировать свои дальнейшие действия. Если вы получаете визу тогда вы бронируете номер в отеле .Если всё хорошо, то вы покупаете билет на самолет.

Если какой-то из шагов не выполняется, то вы полностью отменяете отпуск.

Давайте посмотрим как это будет выглядеть в JavaScript.

Допустим имеется функция applyForVisa(); - подать документы на визу.

Эта функция асинхронная и поэтому она вернет обратно - обещание.

let promise = applyForVisa();

Это обещание мы сохраним в переменной promise.

У обещания есть метод .then() что по-русски можно перевести как далее.

Данный метод принимает два аргумента.


let promise = applyForVisa();

promise.then( resolve, reject );



В качестве первого, принимается функция, которая работает в случае если обещание выполняется. В качестве второго аргумента, принимается функция которая сработает если обещание не будет выполнено.

В зависимости от результата выполнения функции applyForVisa(); сработает либо функция resolve или функция reject.

В нашем случае в качестве функции resolve мы отправляем функцию bookHotel или забронировать отель. В качестве функции reject мы отправляем cancelVacation, то есть отменить отпуск.



Как я уже сказал, результатом applyForVisa(); является обещание, но нам не обязательно хранить его в переменной, поэтому сразу после вызова функции applyForVisa(); мы можем использовать метод .then() и в качестве аргументов отправить соответствующие функции.



В функцию .then() не обязательно отправлять два аргумента. Мы можем отправить только один - bookHotel на тот случай если обещание будет выполнено.

Если же обещание не будет выполнено, то мы можем использовать другой метод у объекта promise.

Он называется .catch().


applyForVisa()
 .then( bookHotel )
 .catch( cancelVacation );



Он принимает лишь один аргумент, которым будет являться функция, которая должна сработать если обещали не будет выполнено.

В данном случае cancelVacation.

Метод .catch() имеет смысл использовать если у нас имеется несколько шагов.


applyForVisa()
 .then( bookHotel )
 .then( buyTickeys )
 .catch( cancelVacation );



То есть мы бронируем отель - bookHotel.
Далее Мы покупаем билеты buyTickeys
и если вдруг на каком-то из шагов происходит ошибка, то мы и ловим (.catch) функцией cancelVacation.

Заметьте как просто читается код.
  • Подать заявление на визу.
  • Далее - забронировать отель.
  • Далее - купить билеты.
  • В случае если что-то не получится, то - отменить отпуск.
Асинхронный код выглядит так, как будто он синхронный.

По сути, обещания делают тоже самое, что и функции обратного вызова. Более того, мы и используем функции обратного вызова!

Отличается то, как мы пишем код.Его структура.Её гораздо проще понимать.

Теперь, перейдем к созданию собственных обещаний.



                                                                                                                                                             


Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com