Внимание: этот пост находится в стадии разработки и не закончен!

Темы

  1. Языковое введение и история
  2. Типы
  3. Струны
  4. Переменные: let, const или var
  5. Условные операторы и операторы
  6. Петли
  7. Массивы
  8. "Объекты"
  9. Функции: аргументы, IIFE
  10. Функции массива высшего порядка: функции первого класса
  11. Версии ECMAScript(ES)
  12. Стрелочные функции
  13. Занятия
  14. Шаблонные строки, операторspread&Rest и т.д.
  15. Сравнение обратных вызовов, промисов и асинхронного ожидания
  16. Понимание синхронного JS
  17. Асинхронный JS (с использованием обратных вызовов, промисов, асинхронного ожидания)
  18. Предварительные условия для Nodejs и Reactjs

Введение

Введение

JS был создан в 1999 году Бренданом Эйком, когда он был инженером в Netscape.

JavaScript — это однопоточный язык программирования, что означает, что в каждый момент времени может происходить только одно действие. То есть механизм JavaScript может обрабатывать только один оператор за раз в одном потоке.

JS является синхронным, но иногда асинхронным.

JavaScript всегда является синхронным (c, c++ и т. д.) и однопоточным. Если вы выполняете блок кода JavaScript на странице, то другой код JavaScript на этой странице в настоящее время выполняться не будет.

JavaScript является только асинхронным в том смысле, что он может выполнять, например, вызовы Ajax. Вызов Ajax перестанет выполняться, и другой код сможет выполняться до тех пор, пока вызов не вернется (успешно или нет), после чего обратный вызов будет выполняться синхронно. В этот момент никакой другой код выполняться не будет. Это не будет прерывать любой другой код, который в данный момент работает.

Мы поймем синхронный и асинхронный JS и их различия, когда изучим «Асинхронный JavaScript» в разделе 17.

Слабо типизированный язык:

"3" + 5

в строго типизированных языках, таких как Python и Go, потому что они не допускают «приведения типов»: возможности неявного изменения типа значения в определенных контекстах ( например, объединение двух типов с помощью +). Языки со слабой типизацией, такие как JavaScript, не будут вызывать ошибку типа (результат: '35').

JavaScript — это мультипарадигмальный динамический язык с типами и операторами, стандартными встроенными объектами и методами. Его синтаксис основан на языках Java и C — многие структуры из этих языков применимы и к JavaScript. JavaScript поддерживает объектно-ориентированное программирование с прототипами объектов вместо классов (см. подробнее о прототипном наследовании и классах ES2015). JavaScript также поддерживает функциональное программирование — поскольку они являются объектами, функции могут храниться в переменных и передаваться, как и любой другой объект.

Является ли JS открытым исходным кодом или открытым стандартом?

JavaScript — это язык программирования, изначально разработанный компанией Netscape. Он стандартизирован под названием ECMAScript http://www.ecmascript.org. Это отклонение в названии связано с разногласиями между разными компаниями по поводу того, как его называть, когда оно стало стандартизированным.

Существуют различные «движки», которые интерпретируют JavaScript, когда он запускается в браузере. Некоторые из них имеют открытый исходный код (например, «Rhino» используется в Firefox или «V8» используется в Chrome).

Однако вопрос о том, является ли сам JavaScript открытым исходным кодом, немного не соответствует действительности.
«Открытый исходный код» относится к программам, тогда как JavaScript — это язык программирования.
Это открытый стандарт, который в некоторых отношениях является близким приближением — по крайней мере, в том смысле, что это не «собственный» язык, который принадлежит и контролируется одной компанией.

JS — это открытый стандарт, существует множество его реализаций, в том числе с открытым исходным кодом. Эти реализации есть на всех видах компилируемых языков и даже на некоторых некомпилируемых.

Язык — это «спецификация» (стандарт ECMAScript),
а затем существует несколько «реализаций» этого стандарта. Обычно это разные проекты, созданные разными людьми.

javascript, в частности, является реализацией языкового стандарта ECMAScript.

Благодаря открытому стандарту ECMAScript является открытым, но не с открытым исходным кодом. (Языковой стандарт не может быть открытым исходным кодом — это не программа, это документ, описывающий ожидаемое поведение программы — но его можно реализовать.)

ECMA и история

если мы хотим изучить JavaScript, нам нужно понять основы JavaScript и ECMAScript (ES), ECMAScript — это простой стандарт для JavaScript и добавление новых функций в JavaScript,

ECMAScript — это подмножество JavaScript. JavaScript в основном является ECMAScript по своей сути, но основан на нем. Такие языки, как ActionScript, JavaScript, JScript, используют ECMAScript в качестве ядра. Для сравнения, AS/JS/JScript — это 3 разных автомобиля, но все они используют один и тот же двигатель… каждый из их экстерьеров отличается, и для каждого было сделано несколько модификаций, чтобы сделать его уникальным.

История такова: Брендан Эйх создал Mocha, который стал LiveScript, а позже JavaScript. Netscape представил JavaScript компании Ecma International, занимающейся разработкой стандартов, и он был переименован в ECMA-262, также известный как ECMAScript.

Важно отметить, что «JavaScript» Брендана Эйха — это не тот же JavaScript, который является диалектом ECMAScript. Он создал базовый язык, который был переименован в ECMAScript, который отличается от JavaScript, который в настоящее время реализуют поставщики браузеров.

Рождение JavaScript:

Все это произошло за шесть месяцев с мая по декабрь 1995 года. Корпорация Netscape Communications имела сильное присутствие в молодой сети. Его браузер Netscape Communicator набирал обороты как конкурент NCSA Mosaic, первому популярному веб-браузеру. Netscape был основан теми же людьми, которые принимали участие в разработке Mosaic в начале 90-х, и теперь, с деньгами и независимостью, у них была необходимая свобода для поиска дальнейших путей расширения сети. И именно это породило JavaScript.

История JavaScript:

Марк Андриссен, основатель Netscape Communications и член бывшей команды Mosaic, считал, что Интернету нужен способ стать более динамичным. Анимация, взаимодействие и другие формы небольшой автоматизации должны стать частью Интернета будущего. Поэтому Интернету требовался небольшой язык сценариев, который мог бы взаимодействовать с моделью DOM (которая не была высечена на камне, как сейчас). Но, и это было важным стратегическим вызовом в то время, этот язык сценариев не должен быть ориентирован на крупных разработчиков и людей с опытом разработки программного обеспечения. Java также была на подъеме, и скоро Java-апплеты должны были стать реальностью. Таким образом, язык сценариев для Интернета должен обслуживать другой тип аудитории: дизайнеров. Действительно, сеть была статична. HTML был еще молодым и достаточно простым, чтобы его могли понять не-разработчики. Таким образом, все, что должно было стать частью браузера, чтобы сделать Интернет более динамичным, должно быть доступно для непрограммистов. Так родилась идея Мокко. Mocha должен был стать языком сценариев для Интернета. Простой, динамичный и доступный для не-разработчиков, нужно больше слов об истории javaScript, но вы можете прочитать больше в других блогах.

реализации JavaScript:

Когда Sun и Netscape закрыли сделку по изменению названия Mocha/LiveScript на JavaScript, возник большой вопрос: что произойдет с альтернативными реализациями? Действительно, хотя в то время Netscape быстро становился предпочтительным браузером, Microsoft также разрабатывала Internet Explorer. С самых первых дней JavaScript настолько изменил пользовательский опыт, что у конкурирующих браузеров не было другого выбора, кроме как предложить работающее решение, работающую реализацию JavaScript. На данный момент (и очень долгое время) веб-стандарты не были сильны. Поэтому Microsoft реализовала собственную версию JavaScript под названием JScript. Отсутствие «Java» в названии позволило избежать возможных проблем с товарным знаком. Однако JScript отличался не только названием. Небольшие различия в реализации, в частности, в отношении некоторых функций DOM, вызвали колебания, которые будут ощущаться еще много лет в будущем. Войны JavaScript велись на большем количестве фронтов, чем просто имена и временные рамки, и многие из его причуд — просто раны этих войн. Первая версия JScript была включена в Internet Explorer 3.0, выпущенный в августе 1996 года.

Итак, JS может быть асинхронным. Он может быть функциональным. Он может быть объектно-ориентированным. Это может быть на стороне клиента. Это может быть на стороне сервера, и этот список можно продолжить.

Типы

Типы

  • Номер (кастинг, TRUTHY VS FALSY)
  • нить
  • логический
  • нулевой
  • неопределенный
  • символ (ES2015)
  • Объект: функция, массив, дата, регулярное выражение.
  • Также есть несколько встроенных типов Error.

Числа в JavaScript — это «значения двойной точности 64-битного формата IEEE 754», и это имеет некоторые интересные последствия. В JavaScript нет такого понятия, как целое число, поэтому вам нужно быть немного осторожным с арифметикой, если вы привыкли к математике в C или Java.

Кроме того, следите за такими вещами, как:

0.1 + 0.2 == 0.30000000000000004;

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

Поддерживаются стандартные арифметические операторы, включая сложение, вычитание, арифметику по модулю (или остатку) и т.д. Существует также встроенный объект, который мы не упоминали ранее под названием Math, который предоставляет расширенные математические функции и константы:

Math.sin(3.5);
var circumference = 2 * Math.PI * r;

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

parseInt('123', 10); // 123
parseInt('010', 10); // 10

Приведение к числу в Javascript с помощью унарного оператора (+)

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

Унарный плюс (+)

Унарные операторы работают с одиночными операндами. Унарный (+) оператор ничем не отличается, и он предшествует своему операнду.

var positiveOne = +1

Теперь это выглядит как бесполезный код. Но ждать. Посмотрим на его спецификацию из ECMA specs:

Унарный оператор + преобразует свой операнд в числовой тип.

Верно. Так что вам не нужно parseInt или parseFloat все подряд. И вам точно не нужно использовать Number()!

Итак, чтобы преобразовать строку, логическое значение или числовую строку, вы можете просто использовать +

+false  // 0
+‘123’  // 123
+0xBABE // 47806 (Hexadecimal)
+null   // 0
+function(val) {return val } // NaN

Унарный (+) может преобразовывать строковые представления целых и числа с плавающей запятой, а также нестроковых значений true, false и null. Поддерживаются целые числа как в десятичном, так и в шестнадцатеричном формате. Поддерживаются отрицательные числа (но не шестнадцатеричные). Если он не может проанализировать конкретное значение, он будет оцениваться как NaN.

Ограничение:

+''     // NaN
+'123a' // NaN
+{}     // NaN

ПРАВДА ПРОТИВ ЛОЖЬ

Следующие значения всегда ложны:

  • false
  • 0 (ноль)
  • '' или "" (пустая строка)
  • null
  • undefined
  • NaN

Все остальное правда. Это включает:

  • '0' (строка, содержащая один ноль)
  • 'false' (строка, содержащая текст «false»)
  • [] (пустой массив)
  • {} (пустой объект)
  • function(){} («пустая» функция)

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

if (value) {
  // value is truthy
}
else {
  // value is falsy
  // it could be false, 0, '', null, undefined or NaN
}

Струны

Струны

‘hello’.length //5
'hello'.charAt(0)  //'h'
'hello,world'.replace('world','mask') // 'hello,mask'
'hello'.toUpperCase()  // 'HELLO'

переменные

Переменные

Новые переменные в JavaScript объявляются с использованием одного из трех ключевых слов: let, const или var.

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

let a;
let name = 'Santiago';
-----
// myLetVariable is *not* visible out here

for (let myLetVariable = 0; myLetVariable < 5; myLetVariable++) {
  // myLetVariable is only visible in here
}

// myLetVariable is *not* visible out here

const позволяет вам объявлять переменные, значения которых никогда не предназначены для изменения. Переменная доступна из блока, в котором она объявлена.

const Pi = 3.14; // variable Pi is set 
Pi = 1; // will throw an error because you cannot change a constant variable.

var — самое распространенное декларативное ключевое слово. У него нет ограничений, которые есть у двух других ключевых слов. Это потому, что традиционно это был единственный способ объявить переменную в JavaScript. Переменная, объявленная с ключевым словом var, доступна из функции, в которой она объявлена.

областью действия ключевого слова var является вся объемлющая функция.

Другая проблема с ключевым словом var заключается в том, что если вы используете его на верхнем уровне вне функции, оно создает свойство для глобального объекта. поэтому ES6 представил 2 новых ключевых слова для решения этих проблем: let и const. Оба этих ключевых слова определяют переменные, которые относятся к содержащему «блоку», а не к «функции»:

var a; 
var name = 'Santiago';
------------------------
// myVar *is* visible out here
for (var myVar = 0; myVar < 5; myVar++) { 
  // myVar is visible to the whole function 
}
// myVar *is* visible out here

Если вы объявляете переменную, не присваивая ей никакого значения, ее тип будет undefined.

ОБЛАСТЬ ПРИМЕНЕНИЯ в JS

Важным отличием JavaScript от других языков, таких как Java, является то, что в JavaScript блоки не имеют области действия; только функции имеют область действия. Таким образом, если переменная определена с помощью var в составном операторе (например, внутри управляющей структуры if), она будет видна всей функции. Однако, начиная с ECMAScript 2015, объявления let и const позволяют создавать переменные блочной области.

условные операторы

Условные операторы/операторы

Сравнения в JavaScript можно делать с помощью <, >, <= и >=. Они работают как для строк, так и для чисел. Равенство немного менее прямолинейно. Оператор двойного равенства выполняет приведение типов, если вы задаете ему разные типы, иногда с интересными результатами:

123 == '123'; // true
1 == true; // true

Чтобыизбежатьприведения типов, используйте оператор тройного равенства:

123 === '123'; // false
1 === true;    // false

Есть также операторы != и !==.

В JavaScript также есть побитовые операции. Если вы хотите их использовать, они есть.

петли

Петли

  • пока / делать-пока
  • за
  • для .. из (значение)
  • для .. в (индекс)
  • forEach (только для массивов: ES5)

В JavaScript есть while циклов и do-while циклов. Первый хорош для базового зацикливания; второй для циклов, где вы хотите убедиться, что тело цикла выполняется хотя бы один раз:

while (true) {
  // an infinite loop!
}
var input;
do {
  input = get_input();
} while (inputIsNotValid(input));

Цикл for в JavaScript такой же, как в C и Java: он позволяет вам предоставлять управляющую информацию для вашего цикла в одной строке.

for (var i = 0; i < 5; i++) {
  // Will execute 5 times
}

JavaScript также содержит два других известных цикла for: for...of

for (let value of array) {
  // do something with value
}
ex: 
var arr= {10,20,30};
for(let i of arr)
 console.log(i+" ");
// o/p : 10 20 30 

и for...in:

for (let property in object) {
  // do something with object property
}
ex: 
var obj= {a: 1,b:2,c:3};
var s="";
for(var property in obj )
{ s=s+obj[property]; }
 console.log(s);
// o/p : "123"

Другой способ перебора массива, который был добавлен в ECMAScript 5, — это forEach():

// Breaking Bad characters array forEach
['Walter', 'Jesse', 'Hank'].forEach(function(currentValue, index, array) {
  // Do something with currentValue or array[index]
    console.log(currentValue+" ");
});
//o/p: 'Walter Jesse Hank' 

В JavaScript есть тернарный оператор для условных выражений:

var allowed = (age > 18) ? 'yes' : 'no';

массивы

Массивы

Они работают почти так же, как обычные объекты (естественно, доступ к числовым свойствам можно получить только с использованием синтаксиса []), но у них есть одно волшебное свойство, называемое 'length'. Это всегда на единицу больше, чем самый высокий индекс в массиве.

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

var a = new Array(); // "The Alchemist" characters Array
a[0] = 'Santiago';
a[1] = 'Alchemist';
a[2] = 'Fatima';
a[3] = 'Shopkeeper';
a[4] = 'Englishman';
a.length; // 5

Более удобной записью является использование литерала массива:

var a = ['Santiago','Alchemist','Fatima','Shopkeeper','Englishman'];
a.length; // 5

Обратите внимание, что array.length не обязательно является количеством элементов в массиве. Рассмотрим следующее:

var a = ['Santiago','Alchemist','Fatima','Shopkeeper','Englishman'];
a[100] = 'fox';
a.length; // 101

Помните — длина массива на единицу больше, чем самый старший индекс.

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

typeof a[90]; // undefined

Если вы примете во внимание сказанное выше о [] и length, вы можете выполнить итерацию по массиву, используя следующий цикл for:

for (var i = 0; i < a.length; i++) {
  // Do something with a[i]
}

ES2015 представил более лаконичный цикл for...of для итерируемых объектов, таких как массивы:

for (const currentValue of a) {
  // Do something with currentValue
}

Вы также можете перебирать массив с помощью цикла for...in, однако это перебирает не элементы массива, а индексы массива. Кроме того, если кто-то добавил новые свойства Array.prototype, они также будут перебираться таким циклом. Поэтому этот тип цикла не рекомендуется для массивов.

Другой способ перебора массива, который был добавлен с помощью ECMAScript 5, — это forEach():

['Santiago','Alchemist','Fatima','Shopkeeper','Englishman'].forEach(function(currentValue, index, array) {
  // Do something with currentValue or array[index]
});

Если вы хотите добавить элемент в массив, просто сделайте это так:

a.push(item);

объекты

объекты

Объекты JavaScript можно рассматривать как простые наборы пар "имя-значение". Таким образом, они похожи на:

  • Словари на Питоне.
  • Хэши в Perl и Ruby.
  • Хеш-таблицы в C и C++.
  • HashMaps в Java.
  • Ассоциативные массивы в PHP.

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

Часть «имя» — это строка JavaScript, а значение может быть любым значением JavaScript, включая дополнительные объекты. Это позволяет строить структуры данных произвольной сложности.

Существует два основных способа создания пустого объекта:

var obj = new Object();

И:

var obj = {};

Они семантически эквивалентны; второй называется синтаксисом литерала объекта и более удобен. Этот синтаксис также является ядром формата JSON и всегда должен быть предпочтительным.

Синтаксис литерала объекта можно использовать для полной инициализации объекта:

var obj = {
  name: 'Carrot',
  for: 'Max', // 'for' is a reserved word, use '_for' instead.
  details: {
    color: 'orange',
    size: 12
  }
};

Доступ к атрибутам можно связать вместе:

obj.details.color; // orange
obj['details']['size']; // 12

В следующем примере создается прототип объекта (Person) и экземпляр этого прототипа (you).

function Person(name, age) {
  this.name = name;
  this.age = age;
}
// Define an object
var you = new Person('You', 24); 
// We are creating a new person named "You" aged 24.

После создания к свойствам объекта снова можно получить доступ одним из двух способов:

обозначение через точку

// dot notation
obj.name = 'Santiago';
var name = obj.name;

обозначение скобок

// bracket notation
obj['name'] = 'Santiago';
var name = obj['name'];
// can use a variable to define a key
var user = prompt('what is your key?')
obj[user] = prompt('what is its value?')

Они также семантически эквивалентны. Второй метод имеет преимущество в том, что имя свойства предоставляется в виде строки, что означает, что его можно вычислить во время выполнения. Однако использование этого метода предотвращает применение некоторых движков JavaScript и минимизированных оптимизаций. Его также можно использовать для установки и получения свойств с именами, которые являются зарезервированными словами:

obj.for='Santiago';// Syntax-error,because 'for' is a reserved-word
obj['for'] = 'Santiago'; // works fine

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

Начиная с ECMAScript 2015, ключи объекта могут быть определены с помощью переменной с использованием квадратных скобок при создании. {[phoneType]: 12345} можно вместо var userPhone = {}; userPhone[phoneType] = 12345.

Прототип.

Прототип — это объект, который связан с каждой функцией и объектом по умолчанию в JavaScript, где свойство прототипа функции доступно и модифицируемо, а свойство прототипа объекта (также известное как атрибут) невидимый.

Каждая функция по умолчанию включает объект-прототип.

Прототип на JavaScript

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

https://www.tutorialsteacher.com/javascript/prototype-in-javascript

Функции: аргументы,IIFE (немедленно вызываемые функциональные выражения)

Функции: аргументы,IIFE (немедленно вызываемые функциональные выражения)

Наряду с объектами функции являются основным компонентом в понимании JavaScript. Самая основная функция не может быть намного проще:

function add(x, y) {
  var total = x + y;
  return total;
}

Это демонстрирует основную функцию. Функция JavaScript может принимать 0 или более именованных параметров. Тело функции может содержать сколько угодно операторов и может объявлять свои собственные переменные, локальные для этой функции. Оператор return может использоваться для возврата значения в любое время, завершая функцию. Если оператор возврата не используется (или пустой возврат без значения), JavaScript возвращает undefined.

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

add(); // NaN
// You can't perform addition on undefined

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

add(2, 3, 4); // 5
// added the first two; 4 was ignored

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

function add() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum;
}
add(2, 3, 4, 5); // 14

Это на самом деле не более полезно, чем написать 2 + 3 + 4 + 5. Создадим функцию усреднения:

function avg() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
}
avg(2, 3, 4, 5); // 3.5

оператор остальных параметров и оператор спреда

Это довольно полезно, но кажется немного многословным. Чтобы еще немного сократить этот код, мы можем заменить использование массива аргументов на синтаксис остальных параметров. Таким образом, мы можем передавать в функцию любое количество аргументов, сохраняя при этом минимальный код. Оператор остальных параметров используется в списках параметров функции в формате: …переменная, и он будет включать в эту переменную весь список незахваченных аргументов, с которыми была вызвана функция. Мы также заменим цикл for на цикл for…of, чтобы возвращать значения в нашей переменной.

function avg(...args) {
  var sum = 0;
  for (let value of args) {
    sum += value;
  }
  return sum / args.length;
}
avg(2, 3, 4, 5); // 3.5

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

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

function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
// expected output: 6

Например: avg(...numbers)

JavaScript позволяет создавать анонимные функции.

var avg = function() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i < j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
};

Это семантически эквивалентно форме function avg(). Это очень мощный инструмент, так как он позволяет вам поместить полное определение функции в любое место, где вы обычно размещаете выражение. Это позволяет использовать всевозможные хитрые трюки.Вот способ «скрыть» некоторые локальные переменные — например, область видимости блока в C:

var a = 1;
var b = 2;
(function() {
  var b = 3;
  a += b;
})();
a; // 4
b; // 2

JavaScript позволяет вам вызывать функции рекурсивно. Это особенно полезно для работы с древовидными структурами, например, в DOM браузера.

function countChars(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
    count += countChars(child);
  }
  return count;
}

Это подчеркивает потенциальную проблему с анонимными функциями: как их рекурсивно вызывать, если у них нет имени? JavaScript позволяет вам называть функциональные выражения для этого. Вы можете использовать namedIIFE (немедленно вызываемые функциональные выражения), как показано ниже:

var charsInBody = (function counter(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
    count += counter(child);
  }
  return count;
})(document.body);

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

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

Функции массива высшего порядка

Функции массива высшего порядка

Чтобы полностью понять эту концепцию, сначала нужно понять, что такое Функциональное программирование, и понятие Первоклассные функции.

JavaScript, Haskell, Clojure, Scala и Erlang — это лишь некоторые из языков, реализующих функциональное программирование.

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

Первоклассные функции

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

В JavaScript функции — это особый тип объекта. Это Function объектов. Например:

function greeting() {
  console.log('Hello World');
} // Invoking the function
greeting();  // prints 'Hello World'

Чтобы доказать, что функции являются объектами в JavaScript, мы могли бы сделать что-то вроде этого:

// We can add properties to functions like we do with objects
greeting.lang = 'English';// Prints 'English'
console.log(greeting.lang);

Примечание. Хотя это вполне допустимо в JavaScript, это считается вредной практикой. Вы не должны добавлять случайные свойства к объектам функции, используйте объект, если вам нужно.

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

Функции высшего порядка (HOF)

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

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

Например, Array.prototype.map, Array.prototype.filter и Array.prototype.reduce — это некоторые из встроенных в язык функций высшего порядка.

  • КАРТА (Array.prototype.map)
  • ФИЛЬТР ( Array.prototype.filter)
  • УМЕНЬШИТЬ (Array.prototype.reduce)
  • Создание собственной функции высшего порядка

Array.prototype.map

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

Функция обратного вызова, переданная методу map(), принимает 3 аргумента: element, index и array.

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

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

Без функции высшего порядка

const arr1 = [1, 2, 3];
const arr2 = [];
for(let i = 0; i < arr1.length; i++) {
  arr2.push(arr1[i] * 2);
}// prints [ 2, 4, 6 ]
console.log(arr2);

С функцией высшего порядка map

const arr1 = [1, 2, 3];
const arr2 = arr1.map(function(item) {
  return item * 2;
});console.log(arr2);

(мы узнаем о стрелочных функциях в следующем разделе)

Мы можем сделать это еще короче, используя синтаксис стрелочной функции:

const arr1 = [1, 2, 3];
const arr2 = arr1.map(item => item * 2);
console.log(arr2);

Пример 2# Допустим, у нас есть массив, содержащий год рождения разных людей, и мы хотим создать массив, содержащий их возраст. Например:

Без функции высшего порядка

const birthYear = [1975, 1997, 2002, 1995, 1985];
const ages = [];
for(let i = 0; i < birthYear.length; i++) {
  let age = 2018 - birthYear[i];
  ages.push(age);
}// prints [ 43, 21, 16, 23, 33 ]
console.log(ages);

С функцией высшего порядка map

const birthYear = [1975, 1997, 2002, 1995, 1985];
const ages = birthYear.map(year => 2018 - year);
// prints [ 43, 21, 16, 23, 33 ]
console.log(ages);

Массив.прототип.фильтр

Метод filter() создает новый массив со всеми элементами, прошедшими проверку, предоставленную функцией обратного вызова. Функция обратного вызова, переданная методу filter(), принимает 3 аргумента: element, index и array.

Допустим, у нас есть массив, содержащий объекты со свойствами name и age. Мы хотим создать массив, содержащий только совершеннолетних лиц (возраст больше или равен 18).

Без функции высшего порядка

const persons = [
  { name: 'wahed', age: 21},
  { name: 'anas', age: 23},
  { name: 'abrar', age: 22 },
  { name: 'umar', age: 50},
  { name: 'zain', age: 25},
];
const fullAge = [];
for(let i = 0; i < persons.length; i++) {
  if(persons[i].age >= 18) {
    fullAge.push(persons[i]);
  }
}console.log(fullAge);

С функцией высшего порядкаfilter

const fullAge = persons.filter(person => person.age >= 18);
console.log(fullAge);

Array.prototype.reduce

Метод reduce выполняет функцию обратного вызова для каждого члена вызывающего массива, что приводит к одному выходному значению. Метод сокращения принимает два параметра:

  1. функция редуктора (обратный вызов),
  2. и необязательный initialValue.

Функция редуктора (обратный вызов) принимает четыре параметра: accumulator, currentValue, currentIndex, sourceArray.

Если указано initialValue, то accumulator будет равно initialValue, а currentValue будет равно первому элементу в массиве.

Если initialValue не указан, то accumulator будет равен первому элементу в массиве, а currentValue будет равен второму элементу в массиве.

Допустим, нам нужно суммировать массив чисел:

С функцией высшего порядкаreduce

const arr = [5, 7, 1, 8, 4];
const sum = arr.reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
});
// prints 25
console.log(sum);

Каждый раз, когда функция редуктора вызывается для каждого значения в массиве, accumulator сохраняет результат предыдущей операции, возвращенный функцией редуктора, а currentValue устанавливается на текущее значение массива. В конце результат сохраняется в переменной sum.

Мы также можем предоставить начальное значение этой функции:

const arr = [5, 7, 1, 8, 4];
const sum = arr.reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
}, 10);// prints 35
console.log(sum);

Без функции высшего порядка

const arr = [5, 7, 1, 8, 4];
let sum = 0;
for(let i = 0; i < arr.length; i++) {
  sum = sum + arr[i];
}// prints 25
console.log(sum);

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

Создание нашей собственной функции высшего порядка

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

const HydDishes = [‘biryani’, ‘nahriPaya’, ‘marag’, ‘shaamii’, ’kofta’ , ’patherKaGosh’ , ‘malaiPaya’ , ‘seekhKebab’];
function mapForEach(arr, fn) { 
 const newArray = [];
  for(let i = 0; i < arr.length; i++) {
    newArray.push(
      fn(arr[i])
    );
  }  return newArray;
}
const lenArray = mapForEach(HydDishes, function(item) {
  return item.length;
});

console.log(lenArray);  // prints [7, 9, 5, 7, 5, 12, 9, 10]

В приведенном выше примере мы создали функцию высшего порядка mapForEach, которая принимает массив и функцию обратного вызова fn. Эта функция перебирает предоставленный массив и вызывает функцию обратного вызова fn внутри вызова функции newArray.push на каждой итерации.

Функция обратного вызова fn получает текущий элемент массива и возвращает длину этого элемента, которая хранится внутри newArray. После завершения цикла for возвращается newArray и присваивается lenArray.

https://blog.bitsrc.io/understanding-higher-order-functions-in-javascript-75461803bad

Версии Ecma Script

Версии и история сценариев Ecma

ECMAScript 6 (2015)

ES6 — это следующее поколение JavaScript, технический комитет ECMA 39 управляет спецификацией ECMA, они обнаружили новые функции в javascript.

ES6 не может компилироваться напрямую в браузерах, поэтому нужен компилятор из ES6 в ES5, для компиляции которого используется babel, он выдает совместимый с браузером javascript.

ES6 включает следующие новые функции:

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

ECMAScript 7 (2016)

Они решили выпускать новую версию ECMAScript каждый год, начиная с 2015 года. Ежегодное обновление означает, что больше не будет больших выпусков, таких как ES6.

ECMAScript 2016 (ES7) представил только две новые функции:

  • Массив.прототип.включает()
  • Оператор возведения в степень

ECMAScript 8 (2017)

На заседании TC39 в январе 2017 года была представлена ​​последняя фича ECMAScript 2017, Общая память и атомарность.

Основные новые функции:

Незначительные новые функции:

ECMAScript 9 (2018)

Основные новые функции:

Новые возможности регулярных выражений:

Другие новые функции:

Стрелочные функции

Стрелочные функции

Стрелочные функции были представлены в ES6 как новый синтаксис для написания функций JavaScript.

Стрелочные функции — также называемые толстыми стрелочными функциями от CoffeeScript (транскомпилируемый язык) — представляют собой более краткий синтаксис для написания функциональных выражений. Они используют новый токен =>, который выглядит как толстая стрелка. Стрелочные функции анонимны и изменяют способ привязки this в функциях.

Стрелочные функции делают наш код более лаконичным и упрощают область видимости функций и ключевое слово this. Это однострочные мини-функции, которые работают так же, как Lambdas в других языках, таких как C# или Python. (См. также лямбды в JavaScript). Используя стрелочные функции, мы избегаем необходимости вводить ключевое слово function, ключевое слово return (оно подразумевается в стрелочных функциях) и фигурные скобки.

1) Несколько параметров (из MDN)

// (param1, param2, paramN) => expression
// ES5
var multiplyES5 = function(x, y) {
  return x * y;
};
// ES6
const multiplyES6 = (x, y) => { return x * y };

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

const multiplyES6 = (x, y) => x * y;

2) Один параметр (из MDN)

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

//ES5
var phraseSplitterEs5 = function phraseSplitter(phrase) {
  return phrase.split(' ');
};
//ES6
const phraseSplitterEs6 = phrase => phrase.split(" ");
console.log(phraseSplitterEs6("ES6 Awesomeness"));  // ["ES6", "Awesomeness"]

3) Без параметров(от MDN)

Скобки необходимы, когда отсутствуют параметры.

//ES5
var docLogEs5 = function docLog() {
    console.log(document);
};
//ES6
var docLogEs6 = () => { console.log(document); };
docLogEs6(); // #document... <html> ….

4) Литеральный синтаксис объекта (возврат литерального выражения объекта)

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

Примечание: тело должно быть заключено в круглые скобки, чтобы различать блок и объект (в обоих случаях используются фигурные скобки).

//ES5
var setNameIdsEs5 = function setNameIds(id, name) {
  return {
    id: id,
    name: name
  };
};

// ES6
var setNameIdsEs6 = (id, name) => ({ id: id, name: name });

console.log(setNameIdsEs6 (4, "Abdul"));   
// Object {id: 4, name: "Abdul"}

5) Пример использования: КАРТА

const smartPhones = [
  { name:'iphone 11 pro', price:649 },
  { name:'Galaxy S11', price:576 },
  { name:'Galaxy Note 10', price:489 }
];

// ES5
var prices = smartPhones.map(function(smartPhone) {
  return smartPhone.price;
});

console.log(prices); // [649, 576, 489]
// ES6
const prices = smartPhones.map(s => s.price);
console.log(prices); // [649, 576, 489]

5) Вариант использования: фильтр

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];

// ES5
var divisibleByThrreeES5 = array.filter(function (v){
  return v % 3 === 0;
});

// ES6
const divisibleByThrreeES6 = array.filter(v => v % 3 === 0);

console.log(divisibleByThrreeES6); // [3, 6, 9, 12, 15]

6) Обещания и обратные вызовы

Вот простой пример цепочки промисов из документации MSDN:

// ES5
aAsync().then(function() {
  returnbAsync();
}).then(function() {
  returncAsync();
}).done(function() {
  finish();
});

Этот код упрощен и, возможно, его легче читать с помощью стрелочных функций:

// ES6
aAsync().then(() => bAsync()).then(() => cAsync()).done(() => finish);

классы

Классы

Классы являются ядром объектно-ориентированного программирования (ООП). Они делают ваш код более безопасным и инкапсулированным. Использование классов придает вашему коду красивую структуру и сохраняет его ориентированность.

class myClass{
    constructor(name,age){
    this.name=name;
    this.age=age;
}
}
const Home= new myClass("said",20);console.log(Home.name)//  said

Литералы шаблонов

В приведенном ниже коде показано, что такое литералы шаблонов в ES6 по сравнению с ES5.

/*IN ES5*/
var name = 'Hello World'; 
var message = 'Hey' + name + ',';/*IN ES6*/
let name = 'Hello World'; 
let message = `Hey ${name},`;

Здесь мы используем символ обратной кавычки. Чтобы добавить заполнитель в литерал шаблона, мы используем синтаксис ${expression}. Вы можете заменить «выражение» любыми выражениями JavaScript. Еще одним преимуществом использования литералов шаблонов является то, что они могут расширять несколько строк.

let author= 'Rudyard Kipling';
let  message = `
if ---by ${name},
If you can keep your head when all about you. Are losing theirs and blaming it on you; ...
If you can dream—and not make dreams your master; If you can think—and not make thoughts your aim; ...
If you can make one heap of all your winnings. ...
If you can talk with crowds and keep your virtue,
Happy learning`;

Разрушение

Деструктуризация — это выражение, которое позволяет нам извлекать свойства из объекта или элемента из массива. Допустим, у нас есть такой адресный объект:

const address = { 
   street: 'Charminar',
   city: 'Hyderabad',
   state: 'telangana'
};

Теперь где-то еще нам нужно получить доступ к этим свойствам и сохранить их значения в наборе переменных: вот версии ES5 и ES6.

//ES5
var street = address.street;
var city = address.city; 
var state = address.state;//ES6
const { street, city, state } = address;

Мы также можем деструктурировать массивы, но мы используем квадратные скобки ([]) вместо фигурных скобок ({}).

//ES5
var values = ['Hello', 'World'];
var first = values[0];
var last = values[1];//ES6
const values = ['Hello', 'World'];
const [first, last] = values;

Параметры по умолчанию

В ES5, если какой-либо из параметров функции не имеет значения, это означает, что мы будем проверять, не определен ли он, и назначать какое-то значение по умолчанию. Это можно легко сделать в ES6, как показано ниже:

//ES5
function getUser (name, year) { 
      year = (typeof year !== ‘undefined’) ? year : 2018; 
      // remainder of the function… 
}//ES6
function getUser (name, year = 2018) {   
      // function body here... 
}

Параметр Rest и оператор Spread

spread: распределяет элементы массива по отдельным значениям.

function getSum(x, y, z){
    console.log(x+y+z);
}let sumArray = [10,20,30];
getSum(...sumArray);

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

Теперь давайте объединим два массива:

var a = [1, 2];
var b = [3, 4];
var c = [...a,...b]
console.log(c);

Вывод будет [1, 2, 3, 4];

Теперь давайте посмотрим на оператор rest.

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

function numbers(x, y, ...z){
    console.log(x, y, z);
}
numbers(1, 2, 3, 4, 5, 6);

Вывод приведенного выше кода будет 1 2 [3, 4, 5, 6].

Как видите, x и y были присвоены значения 1 и 2 соответственно, тогда как остальные параметры были присвоены z. Остальные параметры обозначаются тремя точками перед параметром. Именованный параметр становится массивом, содержащим остальные параметры.

Помните: это те же самые три точки…, то, как и где их использовать, делает эти три точки Растянутыми или Отдыхающими.

Сравнение обратных вызовов, промисов и асинхронного ожидания

Сравнение обратных вызовов, промисов и асинхронного ожидания

Обратные вызовы

Проще говоря: обратный вызов — это функция, которая должна быть выполнена после завершения выполнения другой функции — отсюда и название «обратный вызов».

Проще говоря: в JavaScript функции являются объектами. Из-за этого функции могут принимать функции в качестве аргументов и могут быть возвращены другими функциями. Функции, которые делают это, называются функциями высшего порядка. Любая функция, которая передается в качестве аргумента, называется функцией обратного вызова.

function sum(num1,num2){
   return num1+num2
}
function calculate(num1,num2,sum)
{ 
    //sum is the call back function
       return sum(num1,num2); 
}
var result = calculate(5,6,sum);
console.log(result); // 11

Подробнее об обратных вызовах и приведенных ниже примерах см. в статье: https://medium.com/@fotios.floros/explaining-javascript-callbacks-3d5a9ad52819

  1. Используйте анонимные функции в качестве обратных вызовов
  2. Используйте именованные функции в качестве обратных вызовов
  3. Параметры для функций обратного вызова
  4. Несколько функций обратного вызова
  5. Это необязательно? Это функция?

Обещания

Обещания — это новая функция ES6. Это метод написания асинхронного кода. Его можно использовать, когда мы хотим получить данные из API или когда у нас есть функция, выполнение которой требует времени. Промисы облегчают решение проблемы, поэтому давайте создадим наш первый промис!

let p = new Promise(function(resolve, reject) {      
       if (/* condition */) {       
          resolve(/* value */);  
          // fulfilled successfully    
       }else {       
          reject(/* reason */);  
          // error, rejected    
} });

Обещание принимает два параметра: resolve и reject для обработки ожидаемой ошибки. Чтобы использовать обещание — это означает, что мы хотим обработать значение обещания после его выполнения — мы прикрепляем обработчик к обещанию, используя его метод .then(). Этот метод принимает функцию, которой будет передано разрешенное значение промиса после его выполнения.

var p = new Promise((resolve, reject) => resolve(10)); 
p.then((val) => console.log("fulfilled:", val))  //10  
  .catch((err) => console.log("rejected:", err));

Примечание: функция fetch сама возвращает обещание! (мы узнаем больше о выборке в следующем разделе)

const url='https://jsonplaceholder.typicode.com/posts';
const getData=(url)=>{
    return fetch(url);
}
getData(url).
  then(data=> data.json()).
  then(result=> console.log(result));

асинхронное ожидание

Async и Await — это расширения обещаний.

Асинхронный

Асинхронные функции позволяют нам писать код на основе обещаний, как если бы он был синхронным, но без блокировки потока выполнения. Он работает асинхронно через цикл событий. Асинхронные функции всегда будут возвращать значение. Использование async просто подразумевает, что обещание будет возвращено, и если promise не возвращено, JavaScript автоматически заключает его в разрешенное promise с его значением.

async function firstAsync() {
  return 27;
}
firstAsync().then(alert); // 27

Выполнение приведенного выше кода дает вывод предупреждения как 27, это означает, что был возвращен promise, иначе метод .then() был бы просто невозможен.

Ждите

Оператор await используется для ожидания промиса. Его можно использовать только внутри асинхронного блока. Ключевое слово Await заставляет JavaScript ждать, пока промис не вернет результат. Следует отметить, что это заставляет ждать только функциональный блок async, а не выполнение всей программы.

В приведенном ниже блоке кода показано совместное использование Async Await.

async function firstAsync() {
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => resolve("Now it's done!"), 1000)
    });
    // wait until the promise returns us a value
    let result = await promise; 
  
    // "Now it's done!"
    alert(result); 
    }
};
firstAsync();

Понимание синхронного JS

Понимание синхронного JS

-› Контекст выполнения
-> Стек вызовов

пример:

const second = () => {
  console.log('Hello there!');
}const first = () => {
  console.log('Hi there!');
  second();
  console.log('The End');
}first();

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

Контекст выполнения

Контекст выполнения — это абстрактное понятие среды, в которой оценивается и выполняется код JavaScript. Всякий раз, когда какой-либо код запускается в JavaScript, он запускается внутри контекста выполнения.

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

Стек вызовов

Стек вызовов, как следует из его названия, представляет собой стек со структурой LIFO (последним пришел, первым обслужен), который используется для хранения всего контекста выполнения, созданного во время выполнения кода.

JavaScript имеет один стек вызовов, потому что это однопоточный язык программирования. Стек вызовов имеет структуру LIFO, что означает, что элементы могут быть добавлены или удалены только из вершины стека.

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

const second = () => {
  console.log('Hello there!');
}const first = () => {
  console.log('Hi there!');
  second();
  console.log('The End');
}first();

Вызов стека для приведенного выше кода

Итак, что здесь происходит?

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

Затем console.log('Hi there!') помещается на вершину стека, а когда он заканчивается, он извлекается из стека. После него мы вызываем second(), поэтому функция second() помещается на вершину стека.

console.log('Hello there!') помещается на вершину стека и извлекается из стека по завершении. Функция second() завершается, поэтому она извлекается из стека.

console.log(‘The End’) помещается на вершину стека и удаляется по завершении. После этого функция first() завершается, поэтому она удаляется из стека.

В этот момент программа завершает свое выполнение, поэтому глобальный контекст выполнения (main()) извлекается из стека.

Сравнение обратных вызовов, промисов, асинхронного ожидания

Обратные вызовы

const Func = (firstName,callBack) => {
  setTimeout( () => {
     if(!firstName) 
         return callBack(new Error('no firstName Provided'));
     const fullName = `${firstName} wahed`;
      return callBack(fullName);
   }, 2000);
}
Func("Abdul" , console.log); // Abdul wahed
Func(null , console.log); // 'no firstName Provided'

обещания

const promiseFunc = firstName = > {
  return new Promise(resolve,reject) => {
            setTimeout( () => {
              if(!firstName) 
               return reject(new Error('no firstName Provided'));
              const fullName = `${firstName} wahed`
               return resolve(fullName);
            },2000);
   }
}
promiseFunc('Abdul').then(console.log);  // Abdul wahed
promiseFunc().then(console.log).catch(console.log);
// 'no firstName Provided'

Асинхронное ожидание

const time = ms => {
   return new Promise(resolve => setTimeout(resolve, ms); )
  }
const asyncAwaitFunc = async firstName => {
     await timeout(2000);
     if(!firstName)
        throw new Error('no first name passed');
     const fullName = `${firstName} wahed`;
      return fullName;
}
const resp = ( async () => {
   try {
     console.log( await  asyncAwaitFunc('Abdul'));
   }catch(e) { console.log(e); }
   try {
    console.log( await asyncAwaitFunc() );
   } catch(e) { console.log(e); }

Понимание асинхронного JS (обратные вызовы, промисы, асинхронное ожидание)

Понимание асинхронного JS (обратные вызовы, промисы, асинхронное ожидание)

-› Что блокируется?
-›Цикл событий
-›События DOM, очередь сообщений
-›Очередь заданий ES6/Очередь микрозадач

Как работает асинхронный JavaScript?

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

Что такое блокировка?

Предположим, мы выполняем обработку изображения или сетевой запрос синхронным способом. Например:

const processImage = (image) => {
  /**
  * doing some operations on image
  **/
  console.log('Image processed');
}
const networkRequest = (url) => {
  /**
  * requesting network resource
  **/
  return someData;
}
const greeting = () => {
  console.log('Hello World');
}
processImage(logo.jpg);
networkRequest('www.somerandomurl.com');
greeting();

Обработка изображений и сетевой запрос требуют времени. Поэтому, когда вызывается функция processImage(), это займет некоторое время в зависимости от размера изображения.

Когда функция processImage() завершается, она удаляется из стека. После этого вызывается функция networkRequest() и помещается в стек. Опять же, это также займет некоторое время, чтобы закончить выполнение.

Наконец, когда функция networkRequest() завершается, вызывается функция greeting(), и поскольку она содержит только оператор console.log, а операторы console.log обычно выполняются быстро, функция greeting() немедленно выполняется и возвращается.

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

Итак, каково решение?

Самое простое решение — асинхронные обратные вызовы. Мы используем асинхронные обратные вызовы, чтобы сделать наш код неблокирующим. Например:

const networkRequest = () => {
  setTimeout(() => {
    console.log('Async Code');
  }, 2000);
};
console.log('Hello World');
networkRequest();

Здесь я использовал метод setTimeout для имитации сетевого запроса. Пожалуйста, имейте в виду, что setTimeout не является частью движка JavaScript, это часть того, что известно как веб-API (в браузерах) и API C/C++ (в node.js).

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

Обзор среды выполнения JavaScript

Цикл событий, веб-API и очередь сообщений/очередь задач не являются частью механизма JavaScript, это часть среды выполнения JavaScript браузера или среды выполнения JavaScript Nodejs (в случае Nodejs). В Nodejs веб-API заменены API-интерфейсами C/C++.

Теперь давайте вернемся к приведенному выше коду и посмотрим, как он выполняется асинхронно.

const networkRequest = () => {
  setTimeout(() => {
    console.log('Async Code');
  }, 2000);
};
console.log('Hello World');
networkRequest();
console.log('The End');

Цикл событий

Когда приведенный выше код загружается в браузер, console.log(‘Hello World’) помещается в стек и извлекается из стека после завершения. Затем встречается вызов networkRequest(), поэтому он помещается на вершину стека.

Вызывается следующая функция setTimeout(), поэтому она помещается на вершину стека. setTimeout() имеет два аргумента: 1) обратный вызов и 2) время в миллисекундах (мс).

Метод setTimeout() запускает таймер 2s в среде веб-API. В этот момент setTimeout() закончился, и он выскочил из стека. После него console.log('The End') заталкивается в стек, выполняется и удаляется из стека после его завершения.

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

Цикл событий

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

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

После этого console.log(‘Async Code’) помещается на вершину стека, выполняется и извлекается из стека. На этом обратный вызов завершен, поэтому он удаляется из стека, и программа наконец завершается.

События ДОМ

Очередь сообщений также содержит обратные вызовы из событий DOM, таких как события щелчка и события клавиатуры. Например:

document.querySelector('.btn').addEventListener('click',(event) => {
  console.log('Button Clicked');
});

В случае событий DOM прослушиватель событий находится в среде веб-API, ожидая определенного события (в данном случае события щелчка), и когда это событие происходит, функция обратного вызова помещается в очередь сообщений, ожидая выполнения. .

Снова цикл событий проверяет, пуст ли стек вызовов, и помещает обратный вызов события в стек, если он пуст и обратный вызов выполняется.

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

Очередь заданий ES6/Очередь микрозадач

В ES6 появилась концепция очереди заданий/очереди микрозадач, которая используется Promises в JavaScript. Разница между очередью сообщений и очередью заданий заключается в том, что очередь заданий имеет более высокий приоритет, чем очередь сообщений, что означает, что обещание задания внутри очереди заданий/очереди микрозадач будут выполняться до обратных вызовов внутри очереди сообщений.

Например:

console.log('Script start');
setTimeout(() => {
  console.log('setTimeout');
}, 0);
new Promise((resolve, reject) => {
    resolve('Promise resolved');
  }).then(res => console.log(res))
    .catch(err => console.log(err));console.log('Script End');

Вывод:

Script start
Script End
Promise resolved
setTimeout

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

Возьмем другой пример, на этот раз с двумя обещаниями и двумя setTimeout. Например:

console.log('Script start');
setTimeout(() => {
  console.log('setTimeout 1');
}, 0);
setTimeout(() => {
  console.log('setTimeout 2');
}, 0);
new Promise((resolve, reject) => {
    resolve('Promise 1 resolved');
  }).then(res => console.log(res))
    .catch(err => console.log(err));
new Promise((resolve, reject) => {
    resolve('Promise 2 resolved');
  }).then(res => console.log(res))
    .catch(err => console.log(err));
console.log('Script End');

Это печатает:

Script start
Script End
Promise 1 resolved
Promise 2 resolved
setTimeout 1
setTimeout 2

Мы видим, что два промиса выполняются перед обратными вызовами в setTimeout, потому что цикл событий отдает приоритет задачам в очереди микрозадач над задачами в очереди сообщений/очереди задач.

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

Например:

console.log('Script start');
setTimeout(() => {
  console.log('setTimeout');
}, 0);
new Promise((resolve, reject) => {
    resolve('Promise 1 resolved');
  }).then(res => console.log(res));
new Promise((resolve, reject) => {
  resolve('Promise 2 resolved');
  }).then(res => {
       console.log(res);
       return new Promise((resolve, reject) => {
         resolve('Promise 3 resolved');
       })
     }).then(res => console.log(res));
console.log('Script End');

Это печатает:

Script start
Script End
Promise 1 resolved
Promise 2 resolved
Promise 3 resolved
setTimeout

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

JavaScript-таймеры

Я бы рекомендовал вам ознакомиться со следующей статьей:

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



https://blog.bitsrc.io/understanding-asynchronous-javascript-the-event-loop-74cd408419ff

Получить API

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

Введение в API Fetch: https://www.youtube.com/watch?v=Oive66jrwBs

выборка с использованием ожидания (ES6)

const data= await fetch("localhost:3000/answer");
 
 if(data.reply=="icecream")
  {
     console.log(“Chalo,Famous ki Pot Icecream“);
}
  else if(data.reply=="coffee")
  {
     console.log(“Chalo Nilofer/Nimrah pe chai pete hai!”);
   }
}

В Nodejs нет выборки

Выборка выполняется браузером .

вспомнить в браузере = window.fetch is obj

npm install  node-fetch // library

Вавилон

Вавилон

Babel – это бесплатный компилятор JavaScript с открытым исходным кодом, который в основном используется для преобразованиякода ECMAScript 2015+в обратно совместимую версию JavaScript, которая может выполняться старыми движками JavaScript. .

Babel — популярный инструмент для использования новейших возможностей языка программирования JavaScript.

Ссылки : 3

https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript



Области: https://medium.com/r/?url=https%3A%2F%2Fblog.bitsrc.io%2Funderstanding-asynchronous-javascript-the-event-loop-74cd408419ff