Стандарт ECMAScript 7/8

Разработка динамических веб приложений

Гладкий Максим Валерьевич / github:MaksHladki

Содержание лекции

Стандарт ECMAScript 7

Названия

  • ECMA-262 7th edition
  • ECMAScript 2016
  • ECMAScript 7
  • ES7

Оператор **

                    
var a = 10;
var b = 2;
console.log(a ** b);//100
console.log(Math.pow(a, b));//100
                    
                
                
var a = 10.5;
var b = 2.5;
    
console.log(a ** b);//357.2508309997333
console.log(Math.pow(a, b));//357.2508309997333
                    
                
                
var a = 'test';
var b = 2;
    
console.log(a ** b);//NaN
                    
                

Метод includes для Array

Определяет, содержит ли массив определенный элемент, возвращая в зависимости от этого true/false
                    
arr.includes(searchElement[, fromIndex])
                        
                
                    
console.log([1, 2, 3].includes(2));//true
console.log([1, 2, 3].includes(4));//false
console.log([1, 2, 3].includes(3, 3));//false
console.log([1, 2, NaN].includes(NaN));//true
var arr = ['a', 'b', 'c'];
console.log(arr.includes('c', 1));//true
console.log(arr.includes('c', 3));//false
console.log(arr.includes('c', 100));//false
                        
                    

Еще пример

При отрицательных значениях поиск производится начиная с индекса array.length - fromIndex по возрастанию

                    
//длина массива равна 3
//fromIndex равен -1
//вычисленный индекс равен 3 + (-2) = 1
var arr = ['a', 'b', 'c'];
console.log(arr.includes('a', -2));//false
console.log(arr.includes('b', -2));//true
console.log(arr.includes('c', -2));//true
                        
                    
                    
//длина массива равна 3
//fromIndex равен -100
//вычисленный индекс равен 3 + (-100) = -97
var arr = ['a', 'b', 'c'];
console.log(arr.includes('a', -100));//true
console.log(arr.includes('b', -100));//true
console.log(arr.includes('c', -100));//true
                        
                    

Метод includes для TypedArray

                
typedArr.includes(searchElement[, fromIndex])
                    
                
                
const uint8 = new Uint8Array([10, 20, 30, 40, 50]);
console.log(uint8.includes(20));//true
console.log(uint8.includes(60));//false
console.log(uint8.includes(20, 3));//false
console.log(uint8.includes(40, 3));//true
console.log(uint8.includes(20, -5));//true
                    
                

Стандарт ECMAScript 8

Названия

  • ECMA-262 8th edition
  • ECMAScript 2017
  • ECMAScript 8
  • ES8

Паддинги строк

Метод padStart

Заполняет текущую строку другой сторокой так, что итоговая строка достигает заданной длины. Заполнение осуществляется слева текущей строки
                    
str.padStart(targetLength [, padString])
//targetLength - длина итоговой строки после дополнения текущей.
//Если значение меньше, чем длина текущей строки, 
//текущая строка будет возвращена без изменений.
//padString - cтрока для заполнения текущей строки. 
//Если эта строка слишком длинная для заданной длины, 
//она будет обрезана. Значение по умолчанию - " "

                

Пример

                    
console.log('abc'.padStart(10));//"       abc"
console.log('abc'.padStart(10, "foo"));//"foofoofabc"
console.log('abc'.padStart(6,"123465"));//"123abc"
console.log('abc'.padStart(8, "0"));//"00000abc"
console.log('abc'.padStart(1));//"abc"
console.log('abc'.padStart(-1));//"abc"
                        
                    

Метод padEnd

Заполняет текущую строку с помощью заданной строки, так чтобы результирующая строка достигла заданной длины. Дополнение применяется справа текущей строки
                    
str.padEnd(targetLength [, padString])
//targetLength - длина результирующей строки, 
//после того как текущая строка была дополнена. 
//Если параметр меньше длины текущей строки, 
//то будет возвращена текущая строка.
//padString - строка для дополнения текущей строки. 
//Если строка слишком длинная, 
//она будет урезана и будет применяться ее левая часть.
//" " - значение по умолчанию.
                    
                

Пример

                    
console.log('abc'.padEnd(10));//"abc       "
console.log('abc'.padEnd(10, "foo"));//"abcfoofoof"
console.log('abc'.padEnd(6,"123465"));//"abc123"
console.log('abc'.padEnd(8, "0"));//"abc00000"
console.log('abc'.padEnd(1));//"abc"
console.log('abc'.padEnd(-1));//"abc"
                        
                    

Асинхронные функции

Callback Hell

                    
    getData(function(a){  
        getMoreData(a, function(b){
            getMoreData(b, function(c){ 
                getMoreData(c, function(d){ 
                    getMoreData(d, function(e){ 
                        ...
                    });
                });
            });
        });
    });
                            
                        

Promise Hell

                    
    getData().then((data) => {
        return getMoreData(data).then((moredata) => {
            return getMoreData(moredata).then(result => {
                ...
            })
        })
    });
                            
                        
                    
    getData()
        .then(resolve, reject)
        .then(resolve, reject)
        .then(resolve, reject)
        .then(resolve, reject)
        .catch(err);
                            
                        

Цель внедрения в стандарт

Упросить использование promises синхронно и воспроизвести некоторое действие над группой Promises. Точно так же как Promises подобны структурированным callback-ам, async/await подобна комбинации генераторов и promises

Объявление async function

Определяет асинхронную функцию, которая возвращает объект AsyncFunction
                    
    async function name([param[, param[, ... param]]]) {
        //function's body
    }
                        
                    

Пример

                    
    //анонимная асинхронная функция
    let main = (async function() {
        let value = await fetch('/');
    })();
                            
                        
                    
    //асинхронная функция
    async function main() {
        let value = await fetch('/');
    };
                            
                        
                    
    //сохранение асинхронной функции в переменную
    let main = async function() {
        let value = await fetch('/');
    };
    
    //асинхронная стрелочная функция
    let main = async () => {let value = await fetch('/');};
                            
                        
                    
    //передача асинхронной функции в качестве параметра
    document.body.addEventListener('click', async function() {
        let value = await fetch('/');
    });        
                            
                        

Конструктор AsyncFunction

Cоздает новый объект async function. В JS любая асинхронная функция фактически является объектом AsyncFunction
                
    new AsyncFunction([arg1[, arg2[, ...argN]],] functionBody)
                        
                    

Пример

                    
function resolveAfter2Seconds(x) {
    return new Promise(resolve => {
        setTimeout(() => {resolve(x);}, 2000);
    });
}

var AsyncFunction = Object
    .getPrototypeOf(async function(){})
    .constructor;

var a = new AsyncFunction(
    'a', 
    'b', 
    `return await resolveAfter2Seconds(a) 
          + await resolveAfter2Seconds(b);`
);

a(10, 20).then(v => {
  console.log(v);//напечатает 30 через 4 секунды
});
                    
                

Пример 1

                    
        async function test()
        {
            console.log(this);
            //Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
        }
        
        const result = test();
        console.log(result instanceof Promise);//true
        console.log(result);
        //Promise {<resolved>: undefined}
                            
                        

Пример 2

                    
        async function pow(a, b)
        {
            return a ** b;
        }
        
        const result = pow(2, 3);
        console.log(result);
        //Promise {<resolved>: 8}
                            
                        

Пример 3

                    
        async function pow(a, b)
        {
            return a ** b;
        }
        
        const promise = pow(2, 3);
        promise.then(
            (result) => console.log(result)//8
        );
                            
                        

Пример 4

                    
        async function pow(a, b)
        {
            return a ** b;
        }
        
        console.log('Begin');
        const promise = pow(2, 3);
        promise.then(
            (result) => console.log(`Result: ${result}`)
        );
        console.log('End');
        
        //Begin
        //End
        //Result: 8
                            
                        

Пример 5

                    
        async function timeout(message, delay = 0) {
            return new Promise(done => {
                setTimeout(() => done(message), delay * 1000);
            });
        }
        
        timeout('Ждем 2 секунды', 2)
            .then(
                message => console.log(message)
            );
        //Ждем 2 секунды
                            
                        

Особенности

  • После вызова, функция async возвращает Promise
  • Когда результат был получен, Promise завершается, возвращая полученное значение
  • Когда функция async выбрасывает исключение, Promise ответит отказом с выброшенным (throws) значением

Оператор await

Используется для ожидания окончания Promise. Может быть использован только внутри async function
                
    [result] = await expression;
    
    //expression - Promise или любое другое ожидаемое значение
    
    //result - полученное из Promise значение, либо само значение, 
    //если оно не является Promise
                        
                    

Особенности

  • Заставляет async-функцию ждать выполнения Promise и продолжать выполнение после возвращения Promise значения
  • Впоследствии возвращает полученное из Promise значение
  • Если типом значения, к которому был применен оператор await, является не Promise, то значение приводится к успешно выполненному Promise
  • Если Promise отклоняется, то await генерирует исключение с отклонённым значением

Пример 1

                    
    async function test(n) {
        var result = await Promise.resolve(n);
        console.log(result);//10
        return result;
    }
    
    console.log(test(10));//Promise {<pending>}
                            
                        

Пример 2

                    
    async function pow(a, b)
    {
        var result = await Math.pow(a, b);
        console.log(result);//8
        return result;
    }
    
    console.log(pow(2, 3));//Promise {<pending>}
                            
                        

Пример 3

                    
    async function pow(a, b)
    {
        console.log(2);
        var result = await Math.pow(a, b);
        
        console.log(3);
        return result;
    }
    
    console.log(1);
    pow(2, 3);
    console.log(4);
    
    //1 2 4 3
                            
                        

Пример 4

                    
    async function pow(a, b)
    {
        var result = await Math.pow(a, b);
        return result;
    }
    
    pow(2, 3).then((result) => console.log(result));//8
                            
                        

Пример 5

                    
    function fetchNumber(maxNumber = 10, delay = 0) {
        return new Promise(resolve => { 
            setTimeout(
                () => resolve(Math.floor(Math.random() * maxNumber)),
                delay * 1000
            );
        });
    }
    
    async function sum(){
        let x = await fetchNumber(10, 1);
        let y = await fetchNumber(10, 2);
        console.log(`(${x}, ${y})`);//(4,7)
        return x + y;
    }
    
    sum().then((result) => console.log(result));//11
                            
                        

Пример 6

                    
    function fetchNumber(maxNumber = 10, delay = 0) {
        return new Promise(resolve => { 
            setTimeout(
                () => resolve(Math.floor(Math.random() * maxNumber)),
                delay * 1000
            );
        });
    }
    
    async function sum(){
        let [x, y, z] = await Promise.all([
            fetchNumber(10, 1),
            fetchNumber(10, 2),
            fetchNumber(10, 3)
        ]);
        console.log(`(${x}, ${y}, ${z})`);//(2,2,1)
        return x + y + z;
    }
    
    sum().then((result) => console.log(result));//5
                            
                        

Пример 7

                    
    async function test(n) {
        var result = await Promise.reject(n);
        console.log(result);//Promise {<pending>}
        return result;
    }
    
    console.log(test(10));
    //Ex: Uncaught (in promise) 10
                            
                        

Пример 8

                    
    async function test(n) {
        try
        {
            var result = await Promise.reject(n);
        }
        catch(e){
            console.log(`Ошибка: ${n}`);//Ошибка: 10
        }
        return result;
    }
        
    console.log(test(10));
                                
                            

Пример 9

                    
    async function test(n) {
        console.log(1);
        
        try
        {
            console.log(2);
            var result = await Promise.reject(n);
            console.log(3);
        }
        catch(e){
            console.log(4);
            console.log(`Ошибка: ${n}`);//Ошибка: 10
        }
        
        console.log(5);
        return result;
    }
        
    console.log(test(10));
    //1 2 4 5
                                
                            

Пример 10

                    
    async function fetchPostContent(postId) {
        
        try{
            const post = await fetch(`/post/${postId}`);
        }
        catch(e){
            console.log(e);
            return null;
        }
        
        return post;
    }
    
    const promise = fetchPostContent('68bb1d77')
        .then((data) => console.log(data));
    //GET http://localhost:4000/post/68bb1d77 404 (Not Found)
    //Uncaught (in promise) ReferenceError: post is not defined
                            
                        

Пример 11

                    
    async function fetchPostContent(postId) {
        try{
            const response = await fetch(`/post/${postId}`);
            if (!response.ok)
                throw new Error(response.statusText);
                
            const post = await response.json();
        }
        catch(e){
            console.log(e);
            return null;
        }
        return post;
    }
    
    const promise = fetchPostContent('68bb1d77')
        .then((data) => console.log(data));
    //GET http://localhost:4000/post/68bb1d77 404 (Not Found)
    //Error: Not Found
    //null
                            
                        

Пример 12

                    
    async function fetchPostContent(postId) {
        const postResponse = await fetch(`/post/${postId}`);
        const post = await postResponse.json();
        const userResponse = await fetch(`/user/${post.userId}`);
        const user = await userResponse.json();
      
        return {
            post,
            user
        };
    }
    
    const promise = fetchPostContent('68bb1d77')
        .then((data) => ...);
                            
                        

Асинхронные функции и классы

                
    class MyClass {
        async myMethod() {
            let value = await fetch('/');
        }
    }            
                        
                    
                
    let obj = {
        async method() {
            let value = await fetch('/');
        }
    };
                        
                    

Разделение памяти и объект Atomics

Не поддерживается браузерами

Разделение памяти

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

Объект SharedArrayBuffer

                    
        var buffer = new SharedArrayBuffer(length);
        //length - размер, в байтах, default = 0
                            
                        
Разделенная память может быть создана и изменена одновременно в workers или основном потоке. В зависимости от системы (ЦПУ, ОС, браузер) может уйти время пока изменения будут распространены по всем контекстам. Для синхронизации необходимы атомарные операции

Позитивные моменты

  • Повышается скорость обмена данными между воркерами
  • Координация между воркерами становится быстрее и проще (по сравнению с postMessage)

Пример

                    
        var buffer = new SharedArrayBuffer(1024);
        worker.postMessage(buffer);
                                
                            

Объект Atomics

Предоставляет атомарные операции как статические методы при работе с объектом SharedArrayBuffer

Методы

add добавляет представленное значение к текущему по указанной позиции в массиве
and вычисляет побитовое AND в указанной позиции массива
compareExchange сохраняет представленное значение в указанную позицию массива, если оно эквивалентно представленному значению
exchange сохраняет представленное значение в указанную позицию массива. Возвращает предыдущее значение
load возвращает значение из указаной позиции массива
or вычисляет побитовое OR в указанной позиции массивая
store сохраняет представленное значение в указанную позицию массива
sub вычитает представленное значение из текущего по указанной позиции в массиве
xor вычисляет побитовое XOR в указанной позиции массива
wait проверяет, содержится ли в указанной позиции массива представленное значение. Ожидает определенное время и завершает работу, если событие не произошло
wake пробуждает слушателей, которые спят в очереди ожидания в указанной позиции массива
isLockFree оптимизационный примитив, который может быть использован для определения использовать ли блокирующие операции или атомарные

Прочие особенности

Метод Object.values

Возвращает массив значений перечисляемых свойств объекта в том же порядке что и цикл for...in
                
Object.values(obj)
                    
                
                
let obj = { foo: "bar", baz: 42 };
console.log(Object.values(obj));//["bar", 42]
let obj1 = { 100: 3, 10: 2, 0: 1 };
console.log(Object.values(obj1));//[1, 2, 3]
let obj2 = { 100: "a", test: "b", 2: 10 };
console.log(Object.values(obj2));//[10, "a", "b"]
let obj3 = {test: 1, obj : {name : 'test'}};
console.log(Object.values(obj3));//[1, {name : "test"}]
console.log(Object.values("foo"));//["f", "o", "o"]
console.log(Object.values(1000));//[]
console.log(Object.values([1, 2, 3]));//[1, 2, 3]
                    
                

Метод Object.entries

Возвращает массив собственных перечисляемых свойств указанного объекта в формате [key, value], в том же порядке, что и в цикле for...in
                    
Object.entries(obj)
                    
                
                    
let obj = { foo: "bar", baz: 42 };
console.log(Object.entries(obj));
//[["foo", "bar"], ["baz", 42]]
let obj1 = { 100: 3, 10: 2, 0: 1 };
console.log(Object.entries(obj1));
//[["0", 1], ["10", 2], ["100", 3]]
let obj2 = { 100: "a", test: "b", 2: 10 };
console.log(Object.entries(obj2));
//[["2", 10], ["100", "a"], ["test", "b"]]
                    
                

Еще пример

                    
let obj3 = {test: 1, obj : {name : 'test'}};
console.log(Object.entries(obj3));
//[["test", 1], ["obj", [{name : "test"}]]
    
console.log(Object.entries("foo"));
//[["0", "f"], ["1", "o"], ["2", "o"]]
console.log(Object.entries(1000));//[]
console.log(Object.entries([1, 2, 3]));
//[["0", 1], ["1", 2], ["2", 3]]
                    
                

'Висячие' запятые в параметрах функций

                
function test(var1, var2, var3, ) {
    console.log(var1);//1
    console.log(var2);//2
    console.log(var3);//3
    console.log(arguments);//[1, 2, 3]
}
test(1, 2, 3);
                    
                
                
function test(var1, , ) {
    console.log(var1);
    console.log(arguments);
}
test(1, 2, 3);
//Ex. Uncaught SyntaxError: Unexpected token ,
                    
                

'Висячие' запятые при вызове функций

                
function test(var1, var2, var3) {
    console.log(var1);//1
    console.log(var2);//2
    console.log(var3);//3
    console.log(arguments);//[1, 2, 3]
}
test(1, 2, 3, );
                    
                
                
function test(var1) {
    console.log(var1);
    console.log(arguments);
}
test(1, , , );
//Ex. Uncaught SyntaxError: Unexpected token ,
                    
                

'Висячие' запятые и...

                
let obj = { a:'b', b: 'c', }
console.log(obj);//{a: "b", b: "c"}
const obj1 = {
    print: function (){console.log(this);}
    , 
}
obj1.print();//{print: ƒ}
var arr =[1, 2, 3, ];//length = 3
console.log(arr);//[1, 2, 3]
console.log(arr[3]);//undefined
var arr1 = [1, 2, 3, , , ];//length = 5
console.log(arr1);//[1, 2, 3, empty × 2]
console.log(arr1[4]);//undefined
                    
                

Метод Object.getOwnPropertyDescriptors

Возвращает дескриптор свойства переданного объекта. Свойство должно быть определено непосредственно в объекте, а не получено через цепочку прототипов
                
Object.getOwnPropertyDescriptor(obj, prop)
                    
                
                
const obj = {
    name: 'Test',
    get getName() { 
        return this.name; 
    } 
};
console.log(Object.getOwnPropertyDescriptor(obj, 'getName'));
//{
//   configurable: true,
//   enumerable: true,
//   get: ƒ getName(),
//   set: undefined
//}
                    
                

Спасибо за внимание