ES2020 JavaScript использование свойств RestSpread, асинхронная итерация и другие новые функции


Содержание материала:

Версии Javascript

JavaScript был придуман Бренданом Эйхом (Brendan Eich) в 1995 году и стал стандартом ECMA в 1997 году. Официальное название стандарта — ECMA. А официальное названия языка — ECMAScript. С 2015 года версию языка ECMAScript называют по году (ECMAScript 2015).

Редакции ECMAScript

Версия Официальное название Описание
1 ECMAScript 1 (1997) Первая редакция.
2 ECMAScript 2 (1998) Внесены редакционные правки.
3 ECMAScript 3 (1999) Добавлены регулярные выражения.
Добавлен оператор try/catch.
4 ECMAScript 4 Никогда не выходил.
5 ECMAScript 5 (2009) Добавлен «строгий режим».
Добавлена поддержка JSON.
Добавлен String.trim().
Добавлен Array.isArray().
Добавлены методы обхода элементов массива.
5.1 ECMAScript 5.1 (2011) Внесены редакционные правки.
6 ECMAScript 2015 Добавлены ключевые слова let и const.
Добавлены значения параметров по умолчанию.
Добавлен Array.find().
Добавлен Array.findIndex().
7 ECMAScript 2020 Добавлен оператор возведения в степень (**).
Добавлен Array.prototype.includes.
8 ECMAScript 2020 Добавлен «паддинг» строки (дополнение до нужной длины).
Добавлены новые свойства объекта Object.
Добавлены асинхронные функции.
Добавлены разделяемая память и атомарные операции.
9 ECMAScript 2020 Добавлены свойства rest / spread.
Добавлены асинхронные итерации.
Добавлен Promise.finally().
Добавления в объект RegExp.

ECMAScript часто сокращается до ES.

Поддержка браузерами

ECMAScript 3 полностью поддерживается всеми браузерами.

ECMAScript 5 поддерживается всеми современными браузерами.

Поддержка браузерами ES5 (2009)

Браузер Версия Начиная с
Chrome 23 сентябрь 2012
Firefox 21 апрель 2013
IE 9* март 2011
IE / Edge 10 сентябрь 2012
Safari 6 июль 2012
Opera 15 июль 2013

* Internet Explorer 9 не поддерживает директиву ECMAScript 5 «use strict».

Поддержка браузерами ES6 (2015)

Браузер Версия Начиная с
Chrome 58 апрель 2020
Firefox 54 июнь 2020
Edge 14 август 2020
Safari 10 сентябрь 2020
Opera 55 август 2020

Internet Explorer не поддерживает ECMAScript 2015.

Поддержка браузерами ES7 (2020)

Браузер Версия Начиная с
Chrome 68 май 2020
Opera 47 июль 2020

JavaScript / ECMAScript

JavaScript был разработан для Netscape. Первым браузером, поддерживающим JavaScript, стал вышедший в 1996 году браузер Netscape 2. После Netscape компания Mozilla foundation продолжила разработку JavaScript для своих браузеров Firefox. Последняя версия JavaScript это 1.8.5 (идентична ECMAScript 5).

ECMAScript был разработан Ecma International после адаптации JavaScript. Первая редакция ECMAScript вышла в 1997 году.

Следующая таблица показывает, как соотносятся номера версий этих продуктов:

Год JavaScript ECMA Браузер
1996 1.0 Netscape 2
1997 ECMAScript 1 IE 4
1998 1.3 Netscape 4
1999 ECMAScript 2 IE 5
2000 ECMAScript 3 IE 5.5
2000 1.5 Netscape 6
2000 1.5 Firefox 1
2011 ECMAScript 5 IE 9 (за исключением «use strict»)
2011 1.8.5 Firefox 4 (за исключением начальных нулей в parseInt)
2012 IE 10
2012 Chrome 23
2012 Safari 6
2013 Firefox 21
2013 Opera 15
2015 ECMAScript 2015 Частично поддерживается всеми браузерами

Internet Explorer 4 и Netscape 4.06 были первыми браузерами, которые стали поддерживать ECMAScript 1.

Internet Explorer 5 был первым браузером, который стал поддерживать ECMAScript 2.

Internet Explorer 5.5 и Netscape 6 были первыми браузерами, которые стали поддерживать ECMAScript 3.

Internet Explorer 9 и Firefox 3.5 были первыми браузерами, которые стали поддерживать ECMAScript 5. При этом IE 9 не поддерживает директиву ECMAScript 5 «use strict».

Chrome 23, IE 10 и Safari 6 были первыми браузерами с полной поддержкой ECMAScript 5.

Руководство по асинхронным функциям ES7

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

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

В ECMAScript 7 это станет больше, чем просто мечтой: это станет реальностью. Я покажу вам эту реальность — называемую асинхронными функциями — прямо сейчас. Почему мы говорим об этом сейчас? Ведь даже ES6 не был полностью завершен (спецификация была одобрена в июне 2015 года, после выхода статьи — прим. переводчика), так что кто знает, сколько времени пройдет, прежде чем мы увидим ES7. Правда, вы можете использовать эту технологию уже сейчас, и в конце этой статьи я покажу вам как.

Текущее положение дел

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

Примеры

В качестве первого примера рассмотрим очень простой код: вызов асинхронной функции и вывод в консоль ее результата.

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

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

Мы можем сделать то же самое, но элементы будут выведены в консоль в том же порядке, в котором они находились в массиве. Другими словами, следующий пример будет делать асинхронную работу параллельно, а синхронную работу — последовательно:

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

Даже возможность обещаний разворачивать вложенные коллбэки в этом случае не сильно помогает. Запуск неопределенного числа последовательных асинхронных вызовов в любом случае будет неряшливым, что бы вы не делали. Особенно ужасно выглядят все эти выражения return. Если мы передадим массив newValues в обещание вместо того, чтобы сделать его глобальным внутри функции foo(), мы получим еще больше вложенных выражений return.

Разве вы не согласны, что это нужно исправить? Давайте рассмотрим решение.

Спасение в асинхронных фукциях

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

Как мы будем их использовать?

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

Ключевое слово async не просто позволяет использовать await, но также говорит, что данная функция будет возвращать объект Promise. Какое бы значение вы не вернули из асинхронной функции, она всегда фактически вернет объект Promise с этим значением. Чтобы обещание выполнилось неуспешно, нужно бросить исключение. Например:

Мы даже не дошли до самой важной части, а код уже стал более похож на синхронный, поскольку нам больше не нужно возиться с объектом Promise. Мы взяли функцию и заставили ее возвращать обещание, просто добавив ключевое слово async.

Давайте преобразуем функции getValues и asyncOperation:

Очень просто! Теперь давайте рассмотрим лучшую часть всего этого: ключевое слово await. В любой момент внутри асинхронной функции вы можете добавить ключевое слово await, и выполнение функции остановится, пока обещание не будет успешно или неуспешно выполнено. В примере ниже await promisingOperation() вернет результат обещания:

Когда вы вызываете foo, она ждет выполнения функции promisingOperation и выводит либо «Success!», если обещание успешно, либо «Failure!», если неуспешно.

Остается один вопрос: как обработать неуспешное обещание? Ответ просто: нам нужно обернуть вызов в блок try. catch. Если одна из асинхронных операций завершится неуспешно, сработает блок catch.

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

Примеры

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

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

Вы, наверняка, заметили звездочку после последнего выражения await. await* автоматически обернет результат в Promise.all. Однако инструмент, о котором мы поговорим позже, не поддердивает await*, поэтому можно использовать await Promise.all(newValues), как мы и сделаем в следующем примере.

В следующем примере asyncOperation будет вызываться параллельно, но результат будет собираться вместе и выводиться последовательно.

Мне это нравится. Это чистый код. Если убрать все await и async, удалить обертку Promise.all и сделать функции getValues и asyncOperation синхронными, этот код будет работать в точности так же, как если бы он был синхронным. Именно этого, по существу, мы и стремимся достичь.

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

Снова мы делаем внутреннюю функцию асинхронной. Есть одна интересная особенность, которая проявляется в этом коде. Я передал пустой массив в качестве знаения «memo» в функцию reduce, но потом я использовал await c этим значением. Значение, которое используется с await, не обязательно должно быть массивом. Оно может принимать любые значения, но если это не объект Promise, код просто выполняется синхронно. И конечно, после первого прохода, мы уже будем работать с обещанием.

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

Использование асинхронных функций сегодня

Теперь, когда вы получили представление о красоте и удивительности асинхронных функций, вы можете плакать, как делал это я, когда впервые о них узнал. И я плакал не от радости, нет. Я плакал потому, что ES7 появится не раньше, чем я умру! По крайней мере так я себя чувствовал. И тогда я узнал о Traceur.

Traceur написан и поддерживается Google. Это транслятор, конвертирующий код на ES6 в код на ES5. Но он также поддерживает асинхронные функции. Это экспериментальная особенность, поэтому вам нужно явно сказать трянслятору, что вы хотите использовать асинхронные функции. А также стоит тщательно проверить результат трансляции.

Использование транслятора, такого как Traceur, означает, что вы будете отдавать клиенту немного раздутый и уродливый код. Но работать вы будете с чистым ES6/7 кодом, вместо запутаного.

Конечно, размер кода будет больше (в большинстве случаев), чем при ручном написании на ES5, поэтому нужно искать равновесие между поддерживаемым кодом и производительностью.

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

Traceur — это утилита командной строки, которая может быть установлена через NPM:

В основном, Traceur очень прост в использовании, но некоторые опции требуют экспериментов. Нас будет интересовать опция —experimental.

Эту опцию следует использовать, чтобы включить экспериментальные особенности, такие как асинхронные функции. Допустим, у нас есть JavaScript файл (в данном случае main.js) с ES6 кодом и асинхронными функциями, мы можем транслировать данный код:

Вы также можете просто запустить команду выше, опустив —out compiled.js. Вы не увидите ничего, если код не содержит вызовов console.log (или других методов вывода в консоль), но, по крайней мере, вы можете проверить код на наличие ошибок. Чтобы запустить код в браузере, необходимо предпринять несколько шагов:

  • Скачать traceur-runtime.js. Проще всего сделать это через npm: npm install traceur-runtime. Скрипт будет доступен как index.js в папке модуля.
  • Подключить скрипт Traceur Runtime в вашем HTML-файле.
  • Подключить скрипт compiled.js.

После этого код можно запустить!

Автоматизация компиляции

Запускать компиляцию Traceur можно не только вручную из командной строки, но и с помощью таких инструментов, как Grunt или Gulp. Каждый из их этих сборщиков можно настроить таким образом, чтобы он следил за изменениями файлов в проекте и запускал перекомпиляцию после кадого изменения. Подробнее о каждом сборщике можно прочитать в соответствующей документации (про gulp есть отличная статья на нашем сайте — прим. переводчика).

Заключение

Асинхронные функции ES7 позволяют разработчикам избежать ада коллбэков так, как не могут обещания сами по себе. Эта новая особенность языка делает асинхронный код очень похожим на синхронный. Благодаря компиляции уже сегодня можно использовать асинхронные функции. Так чего же вы ждете? Идите и сделайте свой код потрясающим!

Нашли опечатку? Orphus: Ctrl+Enter

© getinstance.info Все права защищены. 2014–2020

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

Как вернуть ответ от асинхронного вызова?

У меня есть функция foo , которая делает запрос Ajax. Как вернуть ответ от foo ?

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

→ Если вы уже поняли проблему, перейдите к возможным решениям ниже.

Эта проблема

A в Ajax означает асинхронный. Это означает, что отправка запроса (или, вернее, получение ответа) исключается из обычного потока выполнения. В вашем примере $.ajax возвращает сразу, а следующий оператор return result; , выполняется до того, как функция, которую вы передали в качестве success обратного вызова, даже была вызвана.

Вот аналогия, которая, надо надеяться, проясняет разницу между синхронным и асинхронным потоком:

синхронный

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

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

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

Асинхронный

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

Это именно то, что происходит, когда вы делаете запрос Ajax.

Вместо ожидания ответа выполнение продолжается немедленно и выполняется оператор после вызова Ajax. Чтобы в конечном итоге получить ответ, вы предоставляете функцию, которая будет вызываться после получения ответа, обратный вызов (заметьте что-нибудь «перезвонить»). Любой оператор, следующий за этим вызовом, выполняется до вызова обратного вызова.

Решение (s)

Примите асинхронную природу JavaScript! Хотя некоторые асинхронные операции предоставляют синхронные аналоги (как и «Ajax»), обычно их не рекомендуется использовать, особенно в контексте браузера.

Почему это плохо, спросите вы?

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

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

Далее мы рассмотрим три различных решения, которые все строятся друг на друге:

  • Обещания с async/await (ES2020+, доступно в старых браузерах, если вы используете транспортер или регенератор)
  • Обратные вызовы (популярные в узле)
  • Обещания с помощью then() (ES2015+, доступно в старых браузерах, если вы используете одну из множества библиотек обещаний)

Все три доступны в текущих браузерах и узле 7+.

ES2020+: обещания с async/await ожиданием

Версия ECMAScript, выпущенная в 2020 году, представила поддержку на уровне синтаксиса для асинхронных функций. С помощью async и await вы можете писать асинхронно в «синхронном стиле». Код все еще асинхронный, но его легче читать/понимать.

async/await основывается на обещаниях: async функция всегда возвращает обещание. await «разворачивает» обещание и либо результат в значении обещание было решены с или выдает ошибку, если обещание было отклонено.

Важно: вы можете использовать await только внутри async функции. Прямо сейчас, на высшем уровне await пока не поддерживается, так что вы, возможно, придется сделать асинхронной IIFE (Сразу Вызывается функция Expression), чтобы начать async контекст.

Вы можете прочитать больше об async и await на MDN.

Вот пример, который основан на задержке выше:

Текущие версии браузера и узла поддерживают async/await . Вы также можете поддерживать более старые среды, преобразовав свой код в ES5 с помощью регенератора (или инструментов, использующих регенератор, таких как Babel).

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

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

В примере с вопросом вы можете заставить foo принимать обратный вызов и использовать его в качестве success обратного вызова. Так это

Здесь мы определили функцию «inline», но вы можете передать любую ссылку на функцию:

Сам foo определяется следующим образом:

callback будет ссылаться на функцию, которую мы передаем foo когда мы ее вызываем, и мы просто передаем ее на success . Т.е. как только Ajax-запрос будет успешным, $.ajax вызовет callback и передаст ответ на обратный вызов (на который можно ссылаться с помощью result , поскольку именно так мы определили обратный вызов).

Вы также можете обработать ответ, прежде чем передать его обратному вызову:

Написание кода с использованием обратных вызовов проще, чем может показаться. В конце концов, JavaScript в браузере сильно зависит от событий (события DOM). Получение ответа Ajax — не что иное, как событие.
Сложности могут возникнуть, когда вам приходится работать со сторонним кодом, но большинство проблем можно решить, просто продумав поток приложения.

ES2015+: обещания с then()

Promise API — это новая функция ECMAScript 6 (ES2015), но он уже имеет хорошую поддержку браузера. Есть также много библиотек, которые реализуют стандартный API Promises и предоставляют дополнительные методы для упрощения использования и композиции асинхронных функций (например, bluebird).

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

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

Вот простой пример использования обещания:

Применительно к нашему вызову Ajax мы могли бы использовать такие обещания:

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

Примечание: отложенные объекты jQuery

Отложенные объекты — это пользовательская реализация обещаний в jQuery (до стандартизации API Promise). Они ведут себя почти как обещания, но выставляют немного другой API.

Каждый Ajax-метод jQuery уже возвращает «отложенный объект» (фактически обещание отложенного объекта), который вы можете просто вернуть из своей функции:

Примечание: обещание получилось

Помните, что обещания и отложенные объекты — это просто контейнеры для будущей стоимости, а не сама стоимость. Например, предположим, у вас было следующее:

Этот код неправильно понимает вышеуказанные проблемы асинхронности. В частности, $.ajax() не замораживает код, пока проверяет страницу «/пароль» на вашем сервере — он отправляет запрос на сервер и, пока ждет, немедленно возвращает объект jQuery Ajax Deferred, а не ответ от сервер. Это означает, что оператор if будет всегда получать этот отложенный объект, обрабатывать его как true и действовать так, как если бы пользователь вошел в систему. Не хорошо.

Но исправить это легко:

Не рекомендуется: синхронные вызовы «Ajax»

Как я уже говорил, некоторые (!) Асинхронные операции имеют синхронные аналоги. Я не защищаю их использование, но для полноты картины, вот как вы должны выполнить синхронный вызов:

Без jQuery

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

JQuery

Если вы используете jQuery, вы можете установить для параметра async значение false . Обратите внимание, что эта опция устарела начиная с jQuery 1.8. Затем можно еще использовать success обратного вызова или доступа к responseText свойство объекта jqXHR:

Если вы используете любой другой метод jQuery Ajax, такой как $.get , $.getJSON и т.д., Вы должны изменить его на $.ajax (поскольку вы можете передавать только параметры конфигурации в $.ajax ).

Берегись! Невозможно сделать синхронный запрос JSONP. JSONP по своей природе всегда асинхронен (еще одна причина, чтобы даже не рассматривать эту опцию).

Если вы не используете jQuery в своем коде, этот ответ для вас

Ваш код должен быть чем-то вроде этого:

Феликс Клинг отлично справился с написанием ответа для людей, использующих jQuery для AJAX, я решил предоставить альтернативу для людей, которые этого не делают.

То, с чем вы сталкиваетесь

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

A в AJAX означает асинхронный. Это означает, что отправка запроса (или, скорее, получение ответа) вынимается из обычного потока выполнения. В вашем примере .send возвращается немедленно, а следующий оператор return result; выполняется до того, как функция, которую вы передали в качестве success обратного вызова, была даже называется.

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

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

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

Это называется CPS. В основном, мы передаем getFive действие, которое необходимо выполнить, когда оно завершается, мы сообщаем нашему кодексу, как реагировать, когда событие завершается (например, наш вызов AJAX или в этом случае тайм-аут).

Который должен предупредить «5» на экране. (Fiddle).

Возможные решения

В основном есть два способа решения этой проблемы:

  • Сделайте вызов AJAX синхронным (позвоните ему SJAX).
  • Реструктурируйте свой код для правильной работы с обратными вызовами.

1. Синхронный AJAX — не делайте этого!!

Что касается синхронного AJAX, не делайте этого! Ответ Felix вызывает некоторые веские аргументы в пользу того, почему это плохая идея. Подводя итог, он заморозит браузер пользователя, пока сервер не вернет ответ и не создаст очень плохой пользовательский интерфейс. Вот еще одно краткое изложение MDN о том, почему:

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

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

Если вам нужно это сделать, вы можете передать флаг: Вот как:

2. Код реструктуризации

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

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

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

Теперь давайте определим foo сам, чтобы действовать соответственно

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

Если вам все еще трудно понять это прочитать руководство по началу работы AJAX в MDN.

XMLHttpRequest 2 (прежде всего прочитайте ответы Бенджамина Грюнбаума и Феликса Клинга)

Если вы не используете jQuery и хотите получить хороший короткий XMLHttpRequest 2, который работает в современных браузерах, а также в мобильных браузерах, я предлагаю использовать его следующим образом:

  1. Это короче, чем все остальные функции, перечисленные.
  2. Обратный вызов устанавливается напрямую (поэтому никаких лишних ненужных замыканий).
  3. Он использует новую загрузку (так что вам не нужно проверять состояние готовности &&)
  4. Есть некоторые другие ситуации, которые я не помню, которые делают XMLHttpRequest 1 раздражающим.

Есть два способа получить ответ на этот вызов Ajax (три с использованием имени переменной XMLHttpRequest):

Или, если по какой-то причине вы bind() обратный вызов с классом:

Или (вышеприведенный лучше анонимные функции всегда проблема):


Нет ничего проще.

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

Поддерживаются все * современные браузеры. И я могу подтвердить, что я использую этот подход, поскольку существует XMLHttpRequest 2. У меня никогда не было никаких проблем во всех браузерах, которые я использую.

onreadystatechange полезен, только если вы хотите получить заголовки в состоянии 2.

Использование имени переменной XMLHttpRequest является еще одной большой ошибкой, поскольку вам нужно выполнить обратный вызов внутри замыканий onload/oreadystatechange, иначе вы его потеряли.

Теперь, если вы хотите что-то более сложное, используя post и FormData, вы можете легко расширить эту функцию:

Опять же. это очень короткая функция, но она получает и публикует.

Или передайте полный элемент формы ( document.getElementsByTagName(‘form’)[0] ):

Или установите некоторые пользовательские значения:

Как видите, я не реализовал синхронизацию. это плохо.

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

Как уже упоминалось в комментарии, использование error && синхронный полностью нарушает смысл ответа. Какой хороший короткий способ правильно использовать Ajax?

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

Но чтобы действительно вывести ошибку, единственный способ — написать неправильный URL, и в этом случае каждый браузер выдает ошибку.

Обработчики ошибок могут быть полезны, если вы устанавливаете пользовательские заголовки, устанавливаете responseType для буфера массива blob или чего-то еще.

Даже если вы передадите POSTAPAPAP в качестве метода, он не выдаст ошибку.

Даже если вы передадите ‘fdggdgilfdghfldj’ в качестве форм-данных, это не выдаст ошибку.

В первом случае ошибка находится внутри displayAjax() в this.statusText как Method not Allowed .

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

междоменный домен не разрешен, выдает ошибку автоматически.

В ответе об ошибке нет кодов ошибок.

Существует только this.type который имеет значение error.

Зачем добавлять обработчик ошибок, если вы полностью не можете контролировать ошибки? Большинство ошибок возвращаются внутри этого в функции обратного вызова displayAjax() .

Итак: нет необходимости в проверке ошибок, если вы можете правильно скопировать и вставить URL. 😉

PS: В качестве первого теста я написал x (‘x’, displayAjax). и он полностью получил ответ. Поэтому я проверил папку, в которой находится HTML, и там был файл с именем «x.xml». Так что даже если вы забудете расширение вашего файла, XMLHttpRequest 2 НАЙДЕТ ЕГО. Я смеюсь

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

Не делай этого.

Если вы хотите на время заблокировать браузер, загрузите красивый большой .txt файл синхронно.

Теперь вы можете сделать

Нет другого способа сделать это не асинхронно. (Да, с циклом setTimeout. но серьезно?)

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

Только если у вас есть страница, где вы всегда загружаете один и тот же XML/JSON или что-то еще, вам нужна только одна функция. В этом случае немного измените функцию Ajax и замените b своей специальной функцией.

Функции выше предназначены для базового использования.

Если вы хотите расширить функцию.

Я использую множество API, и одной из первых функций, которые я интегрирую в каждую HTML-страницу, является первая функция Ajax в этом ответе, только с GET.

Но вы можете многое сделать с XMLHttpRequest 2:

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

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

Если вы используете promises, этот ответ для вас.

Это означает, что AngularJS, jQuery (с отсрочкой), собственная замена XHR (выборка), EmberJS, BackboneJS save или любая библиотека node, которая возвращает promises.

Ваш код должен быть чем-то вроде этого:

Феликс Клинг отлично справился с написанием ответа для людей, использующих jQuery с обратными вызовами для AJAX. У меня есть ответ для родного XHR. Этот ответ предназначен для общего использования promises либо на интерфейсе, либо на бэкэнд.

Основная проблема

Модель JavaScript concurrency в браузере и на сервере с NodeJS/io.js является асинхронной и реактивной.

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

Это означает, что при возврате data обработчик then , который вы определили, еще не выполнил. Это, в свою очередь, означает, что возвращаемое вами значение не было установлено на правильное значение во времени.

Вот простая аналогия проблемы:

Значение data равно undefined , так как часть data = 5 еще не выполнена. Скорее всего, это произойдет через секунду, но к тому времени это не имеет отношения к возвращенному значению.

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

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

Краткое описание promises

A Promise — это ценность с течением времени. promises имеют состояние, они начинаются как ожидающие без значения и могут рассчитывать на:

  • выполнено, что означает, что вычисление выполнено успешно.
  • отклонено, что означает, что вычисление завершилось неудачно.

Обещание может изменять состояния только один раз, после чего он всегда будет находиться в одном и том же состоянии навсегда. Вы можете привязать обработчики then к promises, чтобы извлечь их значение и обработать ошибки. then позволяют цепочки вызовов. promises создаются с использованием API, которые возвращают их. Например, более современная замена AJAX fetch или jQuery $.get возвращает promises.

Когда мы называем .then обещанием и возвращаем что-то от него — мы получаем обещание для обработанного значения. Если мы вернем другое обещание, мы получим удивительные вещи, но позволим удержать наших лошадей.

С promises

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

Теперь, после преобразования setTimeout в использование promises, мы можем использовать then , чтобы он подсчитал:

В принципе, вместо возврата значения, которое мы не можем сделать из-за модели concurrency, мы возвращаем оболочку для значения, которое мы можем развернуть с помощью then . Это как поле, которое можно открыть с помощью then .

Применение этого

Это то же самое для вашего первоначального вызова API, вы можете:

Итак, это работает так же хорошо. Мы узнали, что мы не можем возвращать значения из уже асинхронных вызовов, но мы можем использовать promises и связывать их для выполнения обработки. Теперь мы знаем, как вернуть ответ от асинхронного вызова.

ES2015 (ES6)

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

Является функцией, которая возвращает итератор по последовательности 1,2,3,3,3,3. , которая может быть итерирована. Хотя это интересно само по себе и открывает место для большой возможности, есть один интересный случай.

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

Этот несколько сложный, но очень мощный трюк позволяет нам писать асинхронный код синхронно. Есть несколько «бегунов», которые делают это за вас, написав один из них — несколько коротких строк кода, но выходит за рамки этого ответа. Я буду использовать Bluebird Promise.coroutine здесь, но есть другие обертки, такие как co или Q.async .

Этот метод возвращает само обещание, которое мы можем использовать из других сопрограмм. Например:

ES2020 (ES7)

В ES7 это стандартизировано, сейчас есть несколько предложений, но во всех них вы можете await обещать. Это просто «сахара» (более сильный синтаксис) для предложения ES6 выше, добавив ключевые слова async и await . Вышеприведенный пример:

Он по-прежнему возвращает обещание точно так же:)

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

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

Самое простое решение — создать функцию JavaScript и вызвать его для обратного вызова Ajax success .

Я отвечу ужасным, нарисованным рукой комиком. Второе изображение является причиной того, что result undefined в вашем примере кода.

Angular1

Для людей, которые используют AngularJS, можно справиться с этой ситуацией, используя Promises .

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

Здесь вы можете найти приятное объяснение здесь.

Пример, найденный в docs, указанный ниже.

Angular2 и позже

В Angular2 просмотрите следующий пример, но его рекомендуется использовать Observables с Angular2 .

Вы можете использовать это таким образом,

Смотрите оригинал здесь. Но Typescript не поддерживает native es6 Promises, если вы хотите его использовать, для этого вам может понадобиться плагин.

Кроме того, здесь описывается promises spec.

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

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

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

Параллельно

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

(Мы могли бы покончить с expecting и просто использовать results.length === theArray.length , но это оставляет нас открытым для вероятности того, что theArray будет изменен, пока вызовы theArray . )

Обратите внимание на то, как мы используем index от forEach сохранить результат в results в том же положении, что и запись он относится к, даже если результаты прибывают из строя (так как асинхронные вызовы не обязательно выполнить в том порядке, в котором они были начаты).

Но что, если вам нужно вернуть эти результаты из функции? Как указали другие ответы, вы не можете; вам нужно, чтобы ваша функция принимала и вызывала обратный вызов (или возвращала обещание). Вот версия обратного вызова:

Или здесь версия, возвращающая Promise :

Конечно, если бы doSomethingAsync передавал нам ошибки, мы использовали бы reject чтобы отклонить обещание, когда мы получили ошибку.)

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

Если doSomethingAsync дает вам Promise, вы можете использовать Promise.all :

Если вы знаете, что doSomethingAsync будет игнорировать второй и третий аргументы, вы можете просто передать его непосредственно на map ( map вызывает свой обратный вызов с тремя аргументами, но большинство людей используют только первый большую часть времени):

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

Серии

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

(Поскольку мы выполняем эту работу последовательно, мы можем просто использовать results.push(result) поскольку мы знаем, что не получим результаты не по порядку. Выше мы могли использовать results[index] = result; но в некоторых из следующих примеров у нас нет индекса для использования.)

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

Если doSomethingAsync дает вам Обещание, если вы можете использовать синтаксис ES2020+ (возможно, с помощью транспилятора, такого как Babel), вы можете использовать async функцию с for-of и await :

Если вы не можете использовать синтаксис ES2020+ (пока), вы можете использовать вариант шаблона «Обещание уменьшения» (это более сложный вариант, чем обычное уменьшение Обещания, потому что мы не передаем результат из одного в другое, но вместо этого собираем их результаты в массив):

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

Как видите, getJoke возвращает разрешенное обещание (оно разрешается при возврате res.data.value ). Поэтому вы ждете, пока запрос $ http.get не будет выполнен, а затем будет выполнен console.log(res.joke) (как обычный асинхронный поток).

Это плнкр:

ES6 способ (асинхронно — жду)

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

Поэтому, если вы используете Angular, React или любые другие фреймворки, в которых используется двухстороннее связывание данных или концепция хранения, эта проблема просто решается для вас, поэтому в словом, ваш результат — undefined на первом этапе, поэтому у вас есть result = undefined до того, как вы получите данные, а затем, как только вы получите результат, он будет обновлен и будет присвоен новому значению, которое отклик вашего Аякс звонит.

Но как вы можете сделать это на чистом javascript или jQuery, например, как вы задали в этом вопросе?

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

Например, в вашем случае, который вы используете jQuery, вы можете сделать что-то вроде этого:

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

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

Вот пример того же:

Я использую объект result для хранения значения во время асинхронной операции. Это позволяет получить результат даже после асинхронного задания.

Я использую этот подход много. Мне было бы интересно узнать, насколько хорошо этот подход работает, когда задействован результат обратно через последовательные модули.

В то время как promises и обратные вызовы работают нормально во многих ситуациях, боль в задней части выражает что-то вроде:

В итоге вы пройдете async1 ; проверьте, есть ли name undefined или нет, и соответственно вызовите обратный вызов.

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

Fibers помогает в решении проблемы.

Вы можете проверить проект здесь.

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

В следующем примере, который я написал, показано, как

  • Обрабатывать асинхронные HTTP-вызовы;
  • Дождаться ответа от каждого вызова API;
  • Используйте шаблон Promise;
  • Используйте шаблон Promise.all для объединения нескольких HTTP-вызовов;

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

Контекст. Пример запрашивает конечную точку Spotify Web API для поиска объектов playlist для заданного набора строк запроса:

Для каждого элемента новое Promise будет запускать блок — ExecutionBlock , анализировать результат, планировать новый набор обещаний на основе массива результатов, который представляет собой список user объектов Spotify, и выполнять новый HTTP-вызов внутри ExecutionProfileBlock асинхронно.

Затем вы можете увидеть вложенную структуру Promise, которая позволяет создавать множественные и полностью асинхронные вложенные HTTP-вызовы и объединять результаты каждого подмножества вызовов через Promise.all .

ПРИМЕЧАНИЕ. Для последних API search Spotify потребуется указать токен доступа в заголовках запроса:

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

Я подробно обсудил это решение здесь.

2020 ответ: теперь вы можете делать то, что хотите, в каждом текущем браузере и узле

Это довольно просто:

  • Возвращение обещания
  • Используйте «ожидание», которое скажет JavaScript, ожидая, что обещание будет разрешено в значение (например, ответ HTTP)
  • Добавьте ключевое слово «async» в родительскую функцию

Вот рабочая версия вашего кода:

Вы можете использовать эту пользовательскую библиотеку (написанную с помощью Promise) для выполнения удаленного вызова.

Простой пример использования:

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

Если основная функция обещана

nsynjs будет последовательно оценивать все обещания и помещать результат обещания в свойство data :

Если основная функция не обещана

Шаг 1. Оберните функцию с обратным вызовом в оболочку с поддержкой nsynjs (если у нее обещанная версия, вы можете пропустить этот шаг):

Шаг 2. Ввести синхронную логику в функцию:

Шаг 3. Запустите функцию синхронно через nsynjs:

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

Браузер можно разделить на три части:

3) Очередь событий

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

Теперь давайте подумаем, что мы поставили две функции в очереди: для получения данных с сервера, а другой использует эти данные. Сначала мы нажали функцию serverRequest() в очереди, а затем применили функцию Data(). Функция serverRequest входит в цикл событий и делает вызов серверу, поскольку мы никогда не знаем, сколько времени потребуется для получения данных с сервера поэтому ожидается, что этот процесс займет много времени, и поэтому мы заняли наш цикл событий, таким образом, висящий на нашей странице, что, когда веб-API входит в роль, он принимает эту функцию из цикла событий и имеет дело с сервером, создающим цикл событий, чтобы мы могли выполнять следующую функцию из queue. Следующая функция в очереди — useData(), которая идет в цикле, но из-за отсутствия доступных данных это идет впустую, а выполнение следующей функции продолжается до конца очереди. (Это называется Async-вызовом, то есть мы можем сделать что-то еще, пока мы получить данные)

Предположим, что наша функция serverRequest() имела оператор возврата в коде, когда мы возвращаем данные с сервера. Web API будет выталкивать его в очередь в конце очереди. Поскольку он оказывается в очереди в очереди, мы не можем использовать его данные, поскольку в нашей очереди нет функции, чтобы использовать эти данные. Таким образом, невозможно вернуть что-то из Async Call.

Таким образом, решение этого — обратный вызов или обещание.

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

В моем коде он называется

Прочитайте здесь новые методы в ECMA (2020/17) для создания асинхронного вызова (@Felix Kling Answer on Top) qaru.site/questions/183/.

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

Начнем с простой функции JavaScript:

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

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

Итак, эта задержка просто нарушила функциональность, которую мы ожидали! Но что именно произошло? Ну, это на самом деле довольно логично, если вы посмотрите на код. функция foo() после выполнения ничего не возвращает (таким образом, возвращаемое значение — undefined ), но она запускает таймер, который выполняет функцию через 1 с, чтобы вернуть ‘wohoo’. Но, как вы можете видеть, значение, присвоенное bar, является немедленно возвращаемым материалом из foo(), а не чем-либо другим, что будет позже.

Итак, как нам решить эту проблему?

Позвольте спросить нашу функцию для ОБЕЩАНИЯ. Обещание действительно о том, что оно означает: это означает, что функция гарантирует, что вы обеспечите любой вывод, который она получит в будущем. так что давайте рассмотрим это в действии для нашей маленькой проблемы выше:

Таким образом, краткое изложение — для решения асинхронных функций, таких как вызовы на основе ajax и т.д., вы можете использовать обещание resolve для значения (которое вы намереваетесь вернуть). Таким образом, короче говоря, вы разрешаете значение вместо возврата в асинхронных функциях.

ОБНОВЛЕНИЕ (обещания с асинхронным ожиданием)

Помимо использования then/catch для работы с обещаниями, существует еще один подход. Идея состоит в том, чтобы распознать асинхронную функцию и затем дождаться разрешения обещаний, прежде чем перейти к следующей строке кода. Это все еще только promises под капотом, но с другим синтаксическим подходом. Чтобы прояснить ситуацию, вы можете найти сравнение ниже:

затем/перехват версии:

асинхронная/ожидающая версия:

ECMAScript 6 имеет «генераторы», которые позволяют легко программировать в асинхронном стиле.

Для запуска вышеуказанного кода вы выполните следующее:


Если вам нужно настроить таргетинг на браузеры, которые не поддерживают ES6, вы можете запустить код через Babel или make-compiler для генерации ECMAScript 5.

Обратные вызовы . args завернуты в массив и деструктурированы, когда вы их читаете, чтобы шаблон мог справиться с обратными вызовами, имеющими несколько аргументов. Например, с узлом fs:

Ниже приведены некоторые подходы к работе с асинхронными запросами:

  • Объект Promise Browser
  • Q — библиотека обещаний для JavaScript
  • A + Promises.js
  • jQuery отложен
  • API XMLHttpRequest
  • Использование концепции обратного вызова — как реализация в первом ответе

Пример: jQuery отложенная реализация для работы с несколькими запросами

Короткий ответ. Ваш метод foo() возвращается немедленно, а вызов $ajax() выполняется асинхронно после возвращения функции. Проблема заключается в том, как и где хранить результаты, полученные при вызове async, после его возврата.

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

Обратите внимание, что вызов foo() по-прежнему не возвращает ничего полезного. Однако результат асинхронного вызова теперь будет сохранен в result.response .

Используйте функцию callback() внутри успеха foo() . Попробуйте таким образом. Это просто и легко понять.

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

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

Рассмотрим пример. Вы звоните молочнику и заказываете молоко. Когда это приходит, вы хотите положить его в свой кофе. Вы не можете положить молоко в свой кофе прямо сейчас, потому что его еще нет. Вы должны ждать, пока оно придет, прежде чем положить его в свой кофе. Другими словами, следующее не будет работать:

Потому что у JS нет возможности узнать, что ему нужно дождаться order_milk прежде чем он выполнит put_in_coffee . Другими словами, он не знает, что order_milk является асинхронным —is, что не приведет к появлению молока до некоторого будущего времени. JS и другие декларативные языки выполняют один оператор за другим без ожидания.

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

order_milk , заказывает молоко, затем, когда и только когда оно прибывает, оно вызывает put_in_coffee .

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

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

В этом случае мы могли бы переписать код в вопросе как:

Введите обещания

Это послужило мотивацией для понятия «обещание», которое представляет собой особый тип значения, представляющий будущий или какой-то асинхронный результат. Он может представлять то, что уже произошло, или произойдет в будущем, или может никогда не произойти вообще. У обещаний есть единственный метод, названный then , которому вы передаете действие, которое будет выполнено, когда результат, который представляет обещание, был реализован.

В случае с нашим молоком и кофе мы проектируем order_milk чтобы он возвращал обещание на прибытие молока, а затем определяем put_in_coffee в качестве действия then , как put_in_coffee ниже:

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

Пусть применят обещания к вашей конкретной проблеме. Мы обернем нашу логику запроса внутри функции, которая возвращает обещание:

На самом деле все, что мы сделали, это добавили return к вызову $.ajax . Это работает, потому что jQuery $.ajax уже возвращает что-то вроде обещания. (На практике, не вдаваясь в подробности, мы бы предпочли обернуть этот вызов так, чтобы он возвращал реальное обещание, или использовать какую-то альтернативу $.ajax которая делает это.) Теперь, если мы хотим загрузить файл и дождаться его чтобы закончить, а затем сделать что-то, мы можем просто сказать,

При использовании обещания, мы в конечном итоге прохожу множество функций в then , так что часто бывает полезно использовать более компактные функции со стрелками ES6 стиля:

async ключевое слово

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

но если a асинхронный, с обещаниями мы должны написать

Выше мы говорили: «JS не может знать, что ему нужно дождаться завершения первого вызова, прежде чем он выполнит второй». Разве не было бы хорошо, если бы был какой-то способ сказать JS об этом? Оказывается, есть ключевое слово await , используемое внутри специального типа функции, называемой «асинхронной» функцией. Эта функция является частью будущей версии ES, но она уже доступна в таких транспортерах, как Babel, с правильными настройками. Это позволяет нам просто написать

В вашем случае вы сможете написать что-то вроде

Новые возможности ES2020 о которых должен знать каждый разработчик JavaScript

Девятое издание стандарта ECMAScript, официально известного как ECMAScript 2020 (или ES2020 для краткости), было выпущено в июне 2020 года. Начиная с ES2020, новые версии спецификаций ECMAScript выпускаются ежегодно, а не раз в несколько лет, и содержат меньше новых возможностей, чем основные редакции. Новейшая версия стандарта продолжает ежегодный цикл выпуска. В нем было добавлено четыре новых функции RegExp, свойства rest/spread, асинхронную итерацию и Promise.prototype.finally. Кроме того, ES2020 отменяет синтаксическое ограничение escape-последовательностей из тегированных шаблонов.

Описание этих новые возможностей объясняются в следующих подразделах.

Свойства rest/spread

Одно из наиболее интересных свойств добавленных в ES2015 был оператор spread. Этот оператор делает операции копирования и объединения массивов намного легче. Вместо вызова методов concat() или slice() , можно просто использовать оператор . :

Оператор spread так же удобен в ситуациях массив должен быть передан в качестве отдельного аргумента в функцию. Для примера:

ES2020 дополнительно расширяет этот синтаксис, добавляя свойства spread к литеральным объектам. С помощью свойств spread вы можете скопировать собственные перечисляемые свойства объекта в новый объект. Рассмотрим следующий пример:

В коде, оператор . был использован для получения свойств объекта obj1 и назначению их объекту obj2 . До появления ES2020, подобная конструкция вызвала бы ошибку. Если будут определены несколько свойств с одинаковыми именами то останутся только те которые были последними:

Свойство spread так же предоставляет новый путь объединения двух и более объектов, вместо использования метода Object.assign() :

Однако обратите внимание, что оператор spread не всегда дает тот же результат что и Object.assign() . Рассмотрим следующий код:

В этом коде, метод Object.assign() вызывает унаследованое свойство сеттера. И наоборот, оператор spread игнорирует свойство сеттера.

Важно понимать, что оператор spread копирует только перечисляемые свойства.

В следующем примере, свойство type не будет скопировано потому что его атрибут enumerable установлен в false :

Унаследованные свойство так же игнорируются даже если они перечисляемые:

В этом коде, car2 наследует совойство color от car . Так как оператор spread копирует только собственные свойство объекта, color не копируется.

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

Свойство x в copy1 ссылается на тоже самый объект в памяти что и x в copy2 , поэтому оператор сравнения возвращает true .

Еще одна полезная функция, добавленная в ES2015, – это rest параметры, которые позволяют использовать для представления значений как массив. Например:

Здесь, первый элемент в arr назначен переменной x , а оставшиеся элементы назначены переменной rest . Этот паттерн, называемый деструктуризацией массива, стал настолько популярным, что технический комитет Ecma решил привнести аналогичную функциональность в объекты:

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

Также имейте в виду, что использование нескольких rest в объекте вызывает ошибку, если они не являются вложенными:

Поддержка свойств Rest/Spread

Chrome Firefox Safari Edge
60 55 11.1 No
Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
60 55 11.3 No 8.2 60

Node.js:

  • 8.0.0 (требует флаг —harmony )
  • 8.3.0 (полная поддержка)

Асинхронная итерация

Перебор набора данных является важной частью программирования. До ES2015 JavaScript предоставлял для этой цели операторы for, for … in и while, а также такие методы, как map(), filter() и forEach(). Чтобы программисты могли обрабатывать элементы коллекции по одному, в ES2015 появился интерфейс итератора.

Объект является итеративным, если у него есть свойство Symbol.iterator. В ES2015 объекты строк и коллекций, такие как Set, Map и Array, имеют свойство Symbol.iterator и, следовательно, являются итеративными. Следующий код дает пример того, как получить доступ к итерируемым элементам:

Symbol.iterator – это широко известный символ, определяющий функцию, которая возвращает итератор. Основным способом взаимодействия с итератором является метод next(). Этот метод возвращает объект с двумя свойствами: value и done. Свойство value содержит значение следующего элемента в коллекции. Свойство done содержит true или false, указывающие, достигнут ли конец коллекции.

По умолчанию простой объект не является итеративным, но он может стать итеративным, если вы определите для него свойство Symbol.iterator, как в этом примере:

Этот объект является итеративным, поскольку у него определенно свойство Symbol.iterator. Итератор использует метод Object.keys() для получения массива имен свойств объекта, а затем присваивает его константе values. Он также определяет переменную-счетчик и присваивает ему начальное значение 0. При выполнении итератора он возвращает объект, содержащий метод next(). Каждый раз, когда вызывается метод next(), он возвращает пару со value, содержащим следующий элемент в коллекции, и done хранящее логическое значение, указывающее, достиг ли итератор конца в коллекции.

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

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

Недостатком итераторов является то, что они не подходят для работы с асинхронными источниками данных. Поэтому в ES2020 появились асинхронные итераторы и асинхронные итерируемые объекты -итерации (iterables). Асинхронный итератор отличается от обычного итератора тем, что вместо возврата простого объекта в формате он возвращает промис (promise), которое соответствует . Асинхронная итерируемые объекты (iterable) содержат метод Symbol.asyncIterator (вместо Symbol.iterator), который возвращает асинхронный итератор.

Обратите внимание, что для достижения того же результата невозможно использовать итератор промисей (promises). Хотя обычный синхронный итератор может асинхронно определять values, он все равно должен определять состояние «done» синхронно.

Опять же, вы можете упростить процесс, используя функцию генератора, как показано ниже:

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

Простой способ перебора итерируемого объекта состоит в использовании оператора for … of, но for … of не работает с асинхронными итерируемыми объектами, поскольку value и done не определяются синхронно. По этой причине ES2020 предоставляет for…await…of. Давайте посмотрим на пример:

В этом коде оператор for … await … of неявно вызывает метод Symbol.asyncIterator для объекта коллекции, чтобы получить асинхронный итератор. Каждый раз в цикле вызывается метод итератора next(), который возвращает promise. Как только promise разрешено, свойство value результирующего объекта считывается в переменную x. Цикл продолжается до тех пор, пока свойство done возвращаемого объекта не будет иметь значение true.

Имейте в виду, что оператор for … await … of действует только в асинхронных генераторах и асинхронных функциях. Нарушение этого правила приводит к ошибке SyntaxError.

Метод next() может вернуть promise, которое будет отклонено. Чтобы корректно обработать отклоненное обещание, вы можете заключить оператор for…await…of в оператор try…catch, например:

Поддержка асинхронных итераторов

Chrome Firefox Safari Edge
63 57 12 No
Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
63 57 12 No 8.2 63

Node.js:

  • 8.10.0 (требуется флаг –harmony_async_iteration)
  • 10.0.0 (полная поддержка)

Promise.prototype.finally

Еще одно интересное дополнение в ES2020 – метод finally(). Несколько библиотек ранее реализовывали подобный метод, который оказался полезным во многих ситуациях. Это побудило технический комитет Ecma официально добавить finally() в спецификацию. С помощью этого метода можно выполнять блок кода независимо от состояния promise. Давайте посмотрим на простой пример:

Метод finally() очень полезен когда нужно например что то очистить после операции которая может завершиться успешно или нет. В этом коде, метод finally() просто скрывает спиннер загрузки после получения данных. Вместо то что бы дублировать финальную логику в методах then() и catch() можно прописать этот код в одном методе которых выполнится независимо от статуса выполнения promises.

Вы можете достичь такого же результата используя promise.then(func, func) вместо promise.finally(func) , но нужно будет дублировать одинаковый код в обработчике успешного и ошибочного завершения promises, ну или использовать отдельную переменную для этого:

Как и в случае then() и catch(), метод finally() всегда возвращает promise, поэтому можно связать несколько методов. Обычно finally() используется последним элементом в цепочке, но в определенных ситуациях, например, при выполнении HTTP-запроса, рекомендуется объединить в цепочку другую функцию catch() для обработки ошибок, которые так же могут возникнуть в finally().

Поддержка Promise.prototype.finally

Chrome Firefox Safari Edge
63 58 11.1 18
Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
63 58 11.1 No 8.2 63

Node.js:

10.0.0 (полная поддержка)

Новые свойства RegExp

ES2020 добавленно четыре новых свойства объекта RegExp , которые значительно улучшают возможности обработки строк JavaScript. Новые свойства:

  • s (dotAll) флаг
  • Именованные группы
  • Ретроспективные проверки
  • Unicode property escapes

s (dotAll) Флаг

В регулярных выражениях точка ( . ) специальный символ который соответствует любому символу за исключением символов разрыва строки такими как перехода на новую строку ( \n ) или возврате каретки ( \r ). Обходной путь для сопоставления всех символов, включая разрывы строк, заключается в использовании класса символов с двумя противоположными сокращениями, такими как [\d\D]. Этот класс символов сообщает обработчику регулярных выражений, что нужно найти символ, который является либо цифрой ( \d ), либо не цифрой ( \D ). В результате он соответствует любому символу:

ES2020 вводит режим, в котором точка может быть использована для достижения того же результата. Этот режим можно активировать для каждого регулярного выражения с помощью флага s:

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

Именованные группы

В некоторых шаблонах регулярных выражений использование числа для ссылки на группу может привести к путанице. Например, возьмем регулярное выражение /(\d<4>)-(\d<2>)-(\d<2>)/, соответствующее дате. Поскольку нотация даты в американском английском отличается от британского английского, трудно понять, какая группа относится к дню, а какая группа относится к месяцу:

ES2020 представляет именованные группы, которые используют синтаксис (? …). Таким образом, шаблон для сопоставления с датой можно записать менее двусмысленным образом:

Позже вы можете вызвать именованную группу в шаблоне, используя синтаксис \k . Например, чтобы найти последовательные повторяющиеся слова в предложении, вы можете использовать /\b(? \w+)\s+\k \b/:

Чтобы вставить именованную группу в строку замены метода replace(), нужно будет использовать конструкцию $ . Например:

Ретроспективные проверки (Lookbehind Assertion)

ES2020 привносит в JavaScript assertion (утверждения), которые были доступны в других реализациях регулярных выражений в течение многих лет. Ранее JavaScript поддерживал только предварительные утверждения. Ретроспективные (Lookbehind) утверждение обозначается (?

ES2020 удаляет эти ограничения из тегированных шаблонов и вместо того, чтобы выдавать ошибку, представляет недопустимые escape-последовательности как undefined:

Имейте в виду, что использование недопустимых escape-последовательностей в обычном шаблонном литерале по-прежнему вызывает ошибку:

Поддержка Template Literal Revision

Chrome Firefox Safari Edge
62 56 11 No
Chrome Android Firefox Android iOS Safari Edge Mobile Samsung Internet Android Webview
62 56 11 No 8.2 62

Node.js:

  • 8.3.0 (требует флаг –harmony)
  • 8.10.0 (полная поддержка)

Завершение

Мы рассмотрели несколько ключевых функций, представленных в ES2020, включая асинхронную итерацию, свойства rest/spread, Promise.prototype.finally() и дополнения к объекту RegExp. Хотя некоторые из этих функций еще не полностью реализованы в некоторых браузерах, ими можно пользоваться благодаря транспортерам JavaScript, таким как Babel.

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

H Примеры нововведений в ECMAScript 2020, 2020 и 2020 в черновиках Перевод

.collapse»>Содержание

Трудно отслеживать всё новое, что появляется в JavaScript (ECMAScript). И ещё труднее находить полезные примеры кода. В этой статье я собрал 18 фич, перечисленных в списке выполненных предложений TC39, которые были добавлены в ES2020, ES2020 и ES2020 (финальный драфт), и по каждой из фич привёл полезные примеры. Статья длинная, но не трудная.

1. Array.prototype.includes

Includes — это простой метод экземпляра класса в массиве. Он позволяет легко определять, находится ли в массиве элемент (включая NaN , в отличие от indexOf ).

ECMAScript 2020 или ES7 — Array.prototype.includes()

Любопытный факт: авторы спецификации JavaScript хотели назвать метод contains, но это имя уже застолбила Mootools, поэтому назвали includes.

2. Инфиксный оператор возведения в степень

Для математических операций сложения и вычитания есть инфиксные операторы + и — . А для возведения в степень часто используется оператор ** . В ECMAScript 2020 ** был введён вместо Math.pow .

ECMAScript 2020 or ES7 — Инфиксный оператор возведения в степень **

1. Object.values()

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

ECMAScript 2020 (ES8)— Object.values()

2. Object.entries()

Object.entries() относится к Object.keys , но возвращает не одни лишь ключи, а ключи и значения в виде массива. С помощью этой функции можно очень легко использовать объекты в циклах или преобразовывать объекты в Map.

ECMAScript 2020 (ES8) — Использование Object.entries() в циклах

ECMAScript 2020 (ES8) — Использование Object.entries() для преобразования объекта в Map

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

Для строковых значений было добавлено два метода экземпляров классов — String.prototype.padStart и String.prototype.padEnd . Они позволяют добавлять в начало или конец строкового значения любое другое строковое, в том числе пустое.

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

3.1 Пример с padStart:

Допустим, у нас есть список чисел разной длины. В начале каждого из них нужно добавить “0”, чтобы все элементы стали состоять из 10 цифр. Это можно сделать с помощью padStart(10, ‘0’) .

ECMAScript 2020 — пример с padStart

3.2 Пример с padEnd:

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

Ниже приведён хороший пример одновременного использования padEnd , padStart и Object.entries для красивого вывода данных на экран.

ECMAScript 2020 — padEnd, padStart и Object.Entries

3.3 Использование padStart и padEnd с эмодзи и другими двухбайтными символами

Эмодзи и другие двухбайтные символы представляются с помощью нескольких байтов Unocode. Поэтому padStart и padEnd могут работать не так, как вы ожидаете!

Допустим, нам нужно добавить к строковому значению heart несколько эмодзи , чтобы получилось 10 символов. Результат будет такой:

//Notice that instead of 5 hearts, there are only 2 hearts and 1 heart that looks odd!
‘heart’.padStart(10, » «); // prints.. ‘ heart’

Дело в том, что состоит из двух байтов ( ‘\u2764\uFE0F’ ). Слово heart состоит из 5 символов, так что нужно добавить пять сердечек. Но с помощью ‘\u2764\ JavaScript добавляет только два , а затем используется первый байт \u2764 , в результате получается ещё одно . Итого три .

P.S.: Можете с помощью этой ссылки проверить преобразование Unicode-символов.

4. Object.getOwnPropertyDescriptors

Это метод возвращает всё, что связано со свойствами заданного объекта (включая методы get и set ). Добавлен он, главным образом, для того, чтобы можно было выполнять теневое копирование/клонирование объекта в другой объект, при котором, в отличие от Object.assign , копируются также геттеры и сеттеры.

Object.assign теневым способом копирует всё, за исключением геттеров и сеттеров исходного объекта.

Ниже на примере копирования исходного объекта Car в новый объект ElectricCar показано, чем Object.assign и Object.getOwnPropertyDescriptors отличаются от Object.defineProperties . При использовании Object.getOwnPropertyDescriptors в целевой объект копируются также геттер и сеттер discount .

ECMAScript 2020 (ES8) — Object.getOwnPropertyDescriptors

5. Висячая пунктуация в параметрах функций

Это небольшое нововведение позволяет использовать висячие запятые в конце последнего параметра функции. Зачем? Чтобы с помощью инструментов вроде git blame было видно только новых разработчиков.

Ниже приведён пример проблемы и её решения.

ECMAScript 2020 (ES 8) — Висячая запятая в параметре функции

Примечание: Вы также можете вызывать функции с висячими запятыми!

6. Async/Await

На мой взгляд, это самая важная и полезная фича. Функции async позволяют избежать callback hell и в целом упросить код.

Благодаря ключевому слову async JavaScript-компилятор понимает, что с функцией нужно обращаться иначе. Когда он доходит до слова await, то встаёт на паузу. Компилятор предполагает, что выражение после await возвращает промис, и ждёт, пока промис не будет разрешён или отклонён, после чего продолжает работу.

В этом примере функция getAmount вызывает асинхронные функции getUser и getBankBalance . Можно сделать это в промисе, но использование async/await — более элегантный и простой способ.

ECMAScript 2020 (ES 8) — Базовый пример использования async/await

6.1 Функции Async возвращают промис

Если вы ждёте результат исполнения функции async , то для его получения придётся воспользоваться синтаксисом промиса then .

Допустим, нам нужно журналировать результат в console.log , но не внутри doubleAndAdd . Подождём результата и для его передачи в console.log используем синтаксис then .

ECMAScript 2020 (ES 8) — Функции async/await возвращают промис

6.2 Параллельный вызов async/await

В предыдущем примере мы дважды вызывали await , но каждый раз ждали по одно секунде (всего две секунды). Можно это распараллелить, потому что a и b не зависят друг от друга при использовании Promise.all .

ECMAScript 2020 (ES 8) — Использование Promise.all для распараллеливания async/await

6.3 Обработка ошибок с помощью async/await


Есть разные способы обработки ошибок с помощью async/await .

Способ 1 — Использование try catch в функции

ECMAScript 2020 — Использование try catch в функции async/await

Способ 2 — Ловля каждого выражения await
Каждое выражение await возвращает промис, поэтому можете ловить ошибки в каждой строке.

ECMAScript 2020 — Использование try catch в каждом выражении await

Способ 3 — Ловля всей функции async/await

ECMAScript 2020 — Ловля в конце всей функции async/await

ECMAScript сейчас в находится в стадии финального драфта и выйдет в июне/июле 2020-го. Все описанные ниже фичи включены в Stage-4 и будут частью ECMAScript 2020.

1. Общая память и атомики

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

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

Достигается это с помощью нового типа глобальных объектов, который называется SharedArrayBuffer. Он хранит данные в общей области памяти, поэтому они могут использоваться и основным потоком выполнения JS, и потоками веб-воркеров.

Раньше, если нам нужно было поделиться данными между основным потоком и потоками веб-воркеров, приходилось копировать информацию и отправлять в другой поток с помощью postMessage . Теперь это не нужно!

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

Но применение общей памяти может привести к состоянию гонки. Чтобы этого избежать, внедрили глобальные объекты «атомики». Они предоставляют разные методы для блокирования общей памяти, когда какой-то поток выполнения использует данные. Также атомики предоставляют методы для безопасного обновления данных в общей памяти.

Рекомендуется использовать эту фичу через какую-нибудь библиотеку, но пока что таких библиотек не существует.

Дополнительно можете почитать:

  1. From Workers to Shared Memory — lucasfcosta
  2. A cartoon intro to SharedArrayBuffers — Lin Clark
  3. Shared memory and atomics — Dr. Axel Rauschmayer

2. Убрано ограничение Tagged Template literal

Для начала давайте определимся с понятием “Tagged Template literal” (тегированные шаблонные строки), чтобы лучше разобраться в этой фиче.

Тегированные шаблонные строки появились в ES2015+ и позволяют разработчикам настраивать характер интерполирования строковых значений. Обычно они интерполируются так:

В тегированной строке можно написать функцию для получения прописанных в коде частей строкового литерала, например, [ ‘Hello ‘, ‘!’ ] , и заменяющих переменных, например, [ ‘Raja’] , в виде параметров кастомной функции (например, greet ), и вернуть из неё что угодно.

Ниже показано, как кастомная «тегирующая» функция greet в зависимости от текущего времени присоединяет к строковому литералу выражение “Good Morning!”, “Good afternoon” или “Good evening”, а затем возвращает кастомную строку.

Вероятно, многие теперь захотят использовать «тегированные» функции в разных ситуациях, например, в командах терминала, в HTTP-запросах для компоновки URI, и т.п.

️ Проблема с тегированными шаблонными строками

Проблема в том, что спецификации ES2015 и ES2020 не позволяют использовать символы перехода вроде \u (unicode) и \x (шестнадцатеричный), пока они не будут выглядеть как `\u00A9` или \u <2F804>или \xA9 .

Если у вас есть тегированная функция, внутри которой используются какие-то другие правила (например, правила терминала), требующие применения \ubla123abla , что вовсе не похоже на \u0049 или \u <@F804>, то вы получите синтаксическую ошибку.

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

3. “dotall”-флаг для регулярных выражений

Хотя сегодня в регулярных выражениях точка ( . ) должна соответствовать одному символу, но не соответствует символам новой строки вроде \n \r \f и так далее.

Это расширение позволяет оператору-точке соответствовать любому одиночному символу. Чтобы это работало и ничего не сломало, нужно при создании регулярного выражения использовать флаг \s .

ECMAScript 2020 — dotAll-фича для регулярных выражений, позволяющая символу точки с помощью флага /s соответствовать даже \n

4. Захваты именованных групп регулярных выражений

Это расширение привнесло из языков вроде Python, Java и прочих полезную фичу регулярных выражений под названием «именованные группы». Разработчики могут писать регулярные выражения так, чтобы для разных частей группы в регулярном выражении предоставлялись имена (идентификаторы) в формате ( ? . ). А затем эти имена можно использовать для захвата любой группы.

4.1 Базовый пример именованной группы

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

ECMAScript 2020 — Пример именованных групп в регулярном выражении

4.2 Использование именованных групп внутри регулярного выражения

Можно использовать формат \k для обратной ссылки на группу внутри самого регулярного выражения:

ECMAScript 2020 — Обратное ссылание на именованную группу в регулярном выражении с помощью \k

4.3 Использование именованных групп в String.prototype.replace

Фича с именованными группами встроена и в строковый метод экземпляра класса replace . И благодаря этому можно легко менять местами слова в строке. Например, изменить “firstName, lastName” на “lastName, firstName”.

ECMAScript 2020 — Использование именованных групп в функции replace

5. Rest-свойства объектов

Оператор rest . (три точки) позволяет извлекать свойства объекта, которые ещё не извлечены.

5.1 Можно использовать rest для извлечения только нужных вам свойств

ECMAScript 2020 — Деструктурирование объекта с помощью rest

5.2 Even better, you can remove unwanted items!

ECMAScript 2020 — Object destructuring via rest

6. Spread-свойства объектов

Spread-свойства выглядят так же как и rest-свойства с тремя точками … , но только spread используются для создания (реструктурирования) новых объектов.

Подсказка: оператор spread используется справа от знака равенства, rest — слева.

ECMAScript 2020 — Реструктурирование объекта с помощью rest

7. Lookbehind-утверждения для регулярных выражений

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

Можно использовать группу ( ? ) для положительного утверждения, а группу ( ? ) — для отрицательного утверждения. По сути, оно будет соответствовать до тех пор, пока проходит утверждение -ve .

Положительное утверждение: допустим, нужно удостовериться, что перед словом winning есть знак # (#winning), и регулярное выражение должно вернуть строку “winning”.

ECMAScript 2020 — (? \w , \W , \d и т. д. соответствуют только символам латинского алфавита и числам. А что насчёт чисел в других языках, например, хинди, греческом и прочих?

Нам помогут Unicode Property Escapes. Unicode добавляет к каждому символу свойства с метаданными и использует их для группирования или охарактеризования разных символов.

К примеру, БД Unicode группирует все символы хинди (हिन्दी) по свойству Script со значением Devanagari , а также по свойству Script_Extensions тоже со значением Devanagari . Так что можно поискать по Script=Devanagari и получить все символы хинди.

Devanagari можно использовать и для других языков полуострова Индостан — маратхи, санскрита и так далее.

Начиная с ECMAScript 2020 можно использовать \p вместе с для вывода всех символов языков Индии. Комбинация \p в регулярном выражении находит все Devanagari-символы.

ECMAScript 2020 — \p

Также БД Unicode группирует все греческие символы по свойству Script_Extensions (и Script ) со значением Greek . Так что можно найти эти символы с помощью Script_Extensions=Greek или Script=Greek .

Комбинация \p в регулярном выражении находит все Greek-символы.

ECMAScript 2020 — \p

Более того, БД Unicode хранит разные типы эмодзи с булевым свойствами Emoji , Emoji_Component , Emoji_Presentation , Emoji_Modifier и Emoji_Modifier_Base , чьи значения равны ` true `. Комбинации \ p , \Emoji_Modifier и т.д. соответствуют разным типам эмодзи.

ECMAScript 2020 — Использование \p для разных эмодзи

Наконец, можно использовать заглавный символ перехода \P вместо \p для исключения соответствующих символов.

8. Promise.prototype.finally()

Finally() — новый метод экземпляра класса, добавленный для промисов. Задача в том, чтобы позволить выполнять коллбэки даже после того, как resolve или reject помогут всё вычистить. Коллбэк finally вызывается без каких-либо значений и выполняется несмотря ни на что.

Рассмотрим разные случаи.

ECMAScript 2020 — finally() в случае с разрешением

ECMAScript 2020 — finally() в случае с отказом

ECMASCript 2020 — finally() в случае с ошибкой, брошенной из промиса

ECMAScript 2020 — Случай с ошибкой, брошенной из **catch**

9. Асинхронная итерация

Это чрезвычайно полезная фича. Она позволяет легко создавать циклы асинхронного кода!

У нас появился новый цикл “for-await-of”, в котором можно вызывать функции async , которые в цикле возвращают промисы (или массивы с несколькими промисами). Особенно приятно, что цикл ждёт разрешения каждого промиса, прежде чем выполнять новый цикл.

ECMAScript 2020 — Асинхронный итератор в цикле for-await-of

Различия в синтаксисе между движками выражений JavaScript и Legacy ExtendScript

На этой странице

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

Язык выражений в After Effects основан на JavaScript, который представляет собой реализацию ECMAScript. Движок выражений JavaScript в After Effects 16.0 основан на ECMAScript 2020. Движок выражений Legacy ExtendScript основан на ECMAScript 3 (1999). (Adobe ExtendScript — это также язык, который используется для создания сценариев в After Effects и других приложениях Adobe.)

Вы можете следовать приведенным ниже примерам, а также рекомендациям по созданию выражений, которые работают в обоих движках выражений JavaScript и Legacy ExtendScript.

Основные различия между движками выражений JavaScript и Legacy ExtendScript:

Современный синтаксис JavaScript: улучшения, внесенные в язык выражений

В выражениях можно использовать синтаксис JavaScript из ECMAScript 2020

С момента выхода ECMAScript 3 в язык JavaScript было внесено много дополнений. Появились новые, более компактные и удобочитаемые методы для использования со строками, массивами и объектами. Также появились новые способы объявления переменных и функций, а также параметров по умолчанию, операторов spread и многого другого. Этот документ не охватывает такие изменения, так как это общие изменения языка JavaScript. Ресурсы для изучения многих синтаксических дополнений можно найти по следующим ссылкам:

Дополнительные рекомендуемые, углубленные ресурсы для изучения JavaScript:

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

Для ссылки на другое значение свойства из свойства исходного текста, движок Legacy ExtendScript требует добавить выражение .значение в конце данного свойства. По умолчанию движок выражений JavaScript показывает значение свойства, если только не был явно использован еще один атрибут, такой как .propertyIndex или .name .

Заморозка значений свойств с помощью posterizeTime(0)

В After Effects 16.0 выражение posterizeTime(0) замораживает значение свойства в композиции в момент времени 0. Это относится к обоим движкам выражений JavaScript и Legacy ExtendScript.

Этот подход не является обратно совместимым и может привести к неожиданным результатам в версиях After Effects до 16.0.

Несовместимый устаревший синтаксис

Почти весь синтаксис выражений для движка выражений Legacy ExtendScript совместим с движком выражений JavaScript. Однако есть устаревший синтаксис, который несовместим с движком выражений JavaScript. Иногда это вызвано изменениями синтаксиса в современном варианте JavaScript. В других случаях устаревший синтаксис был удален. Ниже приведены примеры нерабочего и рабочего синтаксисов.

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

Отличается синтаксис if. else

В общем случае рекомендуется всегда писать операторы if. else с разрывами строк и скобками в соответствии с рекомендациями MDN. Движок Legacy ExtendScript был терпим к свободному синтаксису в операторах if. else , однако движок JavaScript требует строгого соблюдения синтаксиса. При использовании движка JavaScript выражения if. else с неверным синтаксисом не обрабатываются.

Не допускается завершать условный оператор без оператора else.

Если выражение завершается оператором if без оператора else , движок JavaScript не обрабатывает такое выражение, выдавая сообщение об ошибке «В выражении используется неопределенное значение (возможно, оно является подписью массива вне диапазона)». Движок Legacy ExtendScript вычисляет следующее выражение равным 100, если параметр time больше 1 секунды. В противном случае оно вычисляется равным 50:

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

Это выражение правильно обрабатывается и движком JavaScript, и движком Legacy ExtendScript.

if и else не могут находиться в одной строке без скобок

Оператор if. else в одной строке без скобок вычисляется движком Legacy ExtendScript, но движок JavaScript выдает сообщение об ошибке, такое как «Ошибка синтаксиса: неожиданный токен else» или «В выражении используется неопределенное значение (возможно, оно является подписью массива вне диапазона)». Сообщение об ошибке зависит контекста и типа свойства.

Движок Legacy ExtendScript вычисляет следующее выражение равным 100, если параметр time больше 1 секунды. В противном случае оно вычисляется равным 50:

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

Все указанные выше решения правильно обрабатывается и движком JavaScript, и движком Legacy ExtendScript.

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

Если выражение заканчивается объявлением функции, движок JavaScript не вычисляет такое выражение, а выдает сообщение об ошибке «Вместо объекта типа «Число», «Массив» или «Свойство» обнаружен объект другого типа». В случае движка JavaScript последний вычисляемый элемент должен возвращать значение, а не объявлять его.

Следующий пример работает для движка Legacy, но не для движка JavaScript:

Если в последней строке вызывается функция (вместо объявления), такое выражение правильно обрабатывается обоими движками:

Сокращенный синтаксис this() не допускается, вместо него используйте thisLayer()

В движке Legacy ExtendScript было разрешено использовать this в качестве сокращения thisLayer. В движке JavaScript форма this ссылается на глобальный объект и вместо нее необходимо использовать thisLayer . Использование this в движке JavaScript обычно приводит к сообщению об ошибке « это не функция ».

В следующем примере для движка Legacy ExtendScript формат this используется для создания сокращенной ссылки на свойство «Положение текстового слоя» из свойства «Исходный текст»:

В движке JavaScript форму this необходимо заменить на thisLayer:

Использование thisLayer совместимо с обоими движками выражений.

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

В случае движка выражений Legacy ExtendScript для доступа к символам текстового свойства можно использовать скобки, как для массива:

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

Этот синтаксис совместим с обоими движками.

Свойства и методы Snake case не допускаются

Устаревшие свойства и методы Snake Case (запись с подчеркиванием вместо camelCase) не поддерживаются механизмом JavaScript. Вместо них следует использовать версии camelCase поскольку они совместимы с обоими движками. Ниже приведен список устаревших выражений Snake Case и соответствующие им выражения camelCase.

Использование eval() с выражениями в двоичной кодировке (.jsxbin)

Выражения, закодированные в двоичном формате ExtendScript (сохраненные как двоичный файл .jsxbin из ExtendScript ToolKit CC), не поддерживаются движком JavaScript.

Чтобы запутать выражение, используйте движок Legacy ExtendScript или другой метод запутывания, совместимый с ECMAScript 2020. Некоторые методы запутывания могут не поддерживаться обоими движками выражений.

Ограниченная поддержка объекта $. (доллар)

Для объекта $. (доллар) методы и свойства характерны для ExtendScript и в основном не поддерживаются движком JavaScript. В этой таблице перечислены неподдерживаемые и поддерживаемые виды использования объекта $. (доллар):

Свойства Snake Case Свойства camelCase Методы Snake Case Методы camelCase

$.engineName (не поддерживается движком Legacy ExtendScript)

Не поддерживаются выражения . reflect.properties, . reflect.methods и toSource()

Выражения reflect.properties и reflect.methods не поддерживаются движком JavaScript. Эти методы характерны для ExtendScript и у них нет прямого эквивалента в JavaScript.

Метод toSource() в JavaScript устарел и не является частью какого-либо стандарта.

Чтобы просмотреть список доступных свойств и методов для любого заданного свойства After Effects, аналогичного тому, которое было предоставлено вышеупомянутыми методами, используйте следующее выражение для свойства «Исходный текст» и свяжите его с нужным свойством, например, используя инструмент «Лассо» вместо thisProperty в строке 1:

Приведенное выше выражение не совместимо с движком Legacy ExtendScript. В нем используются синтаксис и методы, недоступные в ECMAScript 3.

Требования к синтаксису для библиотек выражений .jsx и метода eval() с движком JavaScript

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

Явный префикс thisLayer. или thisProperty. должен быть добавлен к любому собственному методу или атрибуту, который явно не вызывается для слоя или свойства. Такой префикс сообщает движку JavaScript, для какого объекта вызывается метод или атрибут.

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

При использовании движка JavaScript выражения предварительно обрабатываются перед вычислением, чтобы сделать некоторые выражения с синтаксисом для Legacy ExtendScript читаемыми новым движком. Однако такие задачи предварительной обработки не выполняются при вычислении выражений из библиотеки функций выражений .jsx или вызове выражений внутри метода eval() . Указанные выше изменения синтаксиса в таких случаях необходимо вносить вручную. Все эти изменения синтаксиса обратно совместимы с устаревшим движком ExtendScript, поэтому выражение .jsx записанное так, чтобы работать с движком JavaScript, также будет работать с движком Legacy ExtendScript.

Совет по производительности: из-за отсутствия предварительной обработки в случае вызова сложных выражений из библиотеки .jsx с таким синтаксисом и движком JavaScript возможно повышение производительности по сравнению с вызовом такого же выражения непосредственно в свойстве.

Собственные методы с явным префиксом и атрибуты с thisLayer. или thisProperty.

В таблице ниже перечислены методы и атрибуты, для которых требуется префикс. Например, атрибут time необходимо записать в форме thisLayer.time , тогда как метод wiggle() — в форме thisProperty.wiggle() .

Эти префиксы требуются, только если атрибут или метод не вызываются явно в другом слое или свойстве. Например, при вызове thisComp.layer(1).hasParent , добавляется thisLayer. не требуется, так как .hasParent уже явно вызывается в layer(1) .

Не поддерживается $. Поддерживаемые объекты $.
Методы, требующие thisLayer. Атрибуты, требующие thisLayer. Методы, требующие thisProperty. Атрибуты, требующие thisProperty.
comp()
footage()
posterizeTime()
add()
sub()
mul()
div()
clamp()
length()
dot()
normalize()
cross()
lookAt()
timeToFrames()
framesToTime()
timeToTimecode()
timeToFeetAndFrames()
timeToNTSCTimecode()
timeToCurrentFormat()
seedRandom()
random()
gaussRandom()
noise()
degreesToRadians()
radiansToDegrees()
linear()
ease()
easeIn()
easeOut()
rgbToHsl()
hslToRgb()
hexToRgb()
mask()
sourceRectAtTime()
sourceTime()
sampleImage()
toComp()
fromComp()
toWorld()
fromWorld()
toCompVec()
fromCompVec()
toWorldVec()
fromWorldVec()
fromCompToSurface()
time
source
thisProject
colorDepth
transform
anchorPoint
position
scale
rotation
opacity
orientation
rotationX
rotationY
rotationZ
lightTransmission
castsShadows
acceptsShadows
acceptsLights
ambient
diffuse
specular
specularIntensity
shininess
specularShininess
metal
audioLevels
timeRemap
marker
name
width
height
index
parent
hasParent
inPoint
outPoint
startTime
hasVideo
hasAudio
active
enabled
audioActive
cameraOption
pointOfInterest
zoom
depthOfField
focusDistance
aperature
blurLevel
irisShape
irisRotation
irisRoundness
irisAspectRatio
irisDiffractionFringe
highlightGain
highlightThreshold
highlightSaturation
lightOption
intensity
color
coneAngle
coneFeather
shadowDarkness
shadowDiffusion
valueAtTime()
velocityAtTime()
speedAtTime()
wiggle()
temporalWiggle()
smooth()
loopIn()
loopOut()
loopInDuration()
loopOutDuration()
key()
nearestKey()
propertyGroup()
points()
inTangents()
outTangents()
isClosed()
pointsOnPath()
tangentOnPath()
normalOnPath()
createPath()
velocity
speed
numKeys
propertyIndex

Замена математических операторов векторными математическими функциями

Оба движка JavaScript и LegacyExtendScript разрешают перегрузку математических операторов для массивов при использовании такого синтаксиса, как position + [100,100] , однако это не работает для выражений из библиотеки функций выражений .jsx или внутри метода eval() .

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

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

  • Сложение: thisLayer.add(vec1, vec2)
  • Вычитание: thisLayer.sub(vec1, vec2)
  • Умножение: thisLayer.mul(vec, amount)
  • Деление: thisLayer.div(vec, amount)

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

Чтобы найти разницу между wiggle() и значением свойства Position:

Для интерполяции между двумя значениями, подобно linear() , но с расширенным диапазоном за пределами заданного минимума и максимума:

Циклический ввод и вывод свойства Position:

Асинхронное программирование в JavaScript. Использование Deferred и Promise.

Введение

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

Асинхронное программирование в JavaScript

Асинхронное программирование в JavaScript не связано с многопоточностью. JavaScript – однопоточный, это означает, что не существует стандартных языковых конструкций, которые позволят создать в приложении дополнительный поток для выполнения параллельных вычислений (единственная возможность организовать настоящую многопоточность – использовать Web Workers). Асинхронное программирование – стиль программирования, при котором результат работы функций доступен не сразу, а через некоторое время. Асинхронная функция – это функция, после вызова которой JavaScript приложение продолжает работать, потому что функция сразу выполняет возврат. Результат работы асинхронной функции становится известным позже, и для того, чтобы оповестить наше приложении о полученных значениях, асинхронная функция вызывает другую функцию (callback), которую мы передаем в аргументах при запуске.

Например, getDataFromServer(onSuccess); getDataFromServer – асинхронная функция, выполняющая запрос на сервер, onSuccess – callback функция или функция обратного вызова, которая запускается при успешном завершении операции обращения к серверу.

Использование callback функций может привести к появлению проблемы, которую называют Pyramid of Doom – callback функция, в которой вызывается асинхронная функция, которой передается callback функция, и в ней же вызывается асинхронная функция и т.д.

step1( function (result1) <

step2( function (result2) <

step3( function (result3) <

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

Что такое Promise (ECMAScript 6)

Promise – прокси объект, который представляет еще не известное значение (значение будет доступно после завершения асинхронной операции). С Promise можно ассоциировать две функции: первая — для выполнения операции, если асинхронная задача завершилась успешно. И вторая — для операции в случае ошибки.

Promise может находиться в одном из трех состояний:

Например, мы выполняем AJAX запрос с помощью асинхронной функции, которая возвращает Promise. Как только мы выполним запрос, функция создаст Promise, который будет в состоянии pending. Когда сервер вернет ответ, Promise перейдет в состояние fulfilled, если ответ был 200 OK, или в состояние rejected, если статус код был 500 Internal Server Error (или другой код ошибки). При переходе в fullfiled состояние Promise будет содержать ответ от сервера, при переходе в rejected – ошибку или текст ошибки (все зависит от реализации асинхронной функции).

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


Пример использования асинхронной функции download, которая возвращает Promise:

Краткая история JavaScript. Часть 3

Третья и заключительная часть перевода статьи из блога сервиса Auth0 A Brief History of JavaScript. Ключевые моменты: транспайлеры и ECMAScript 2015, немного о новом процессе подготовки обновлений, чего ждать в будущем и как на него повлияют Asm.js и WebAssembly. Перевод подготовлен отделом фронтенд-разработки компании Лайв Тайпинг.

ECMAScript 6 (2015) и 7 (2020): универсальный язык программирования

План ECMAScript Harmony стал основой для последующих улучшений JavaScript. Многие идеи из ECMAScript 4 канули в лету ради всеобщего блага, однако некоторые были пересмотрены. ECMAScript 6, позже переименованный в ECMAScript 2015, должен был принести большие перемены. Почти все обновления, так или иначе влиявшие на синтаксис, были отложены именно для этой версии. К 2015 году комитет, наконец, смог побороть все внутренние разногласия, и ECMAScript 6 увидел свет. Большинство производителей браузеров уже работали над поддержкой этой версии, однако до сих пор не все браузеры имеют полную совместимость с ECMAScript 2015.

Выход ECMAScript 2015 стал причиной резкого роста популярности транспайлеров, таких, как Babel или Traceur. Благодаря тому, что производители этих транспайлеров следили за работой технического комитета, у многих людей появилась возможность испытать преимущества ECMAScript 2015 задолго до его выхода.

Некоторые из основных возможностей ECMAScript 4 были реализованы в этой версии с несколько иным подходом. Например, классы в ECMAScript 2015 — это нечто большее, чем просто синтаксический сахар поверх прототипов. Подобный подход облегчает разработку и внедрение новых возможностей.

Мы (редакция блога Auth0 — прим. пер.) делали подробный обзор новых возможностей ECMAScript 2015 в нашей статье «Краткое изложение возможностей JavaScript». Вы также можете ознакомиться с таблицей совместимости ECMAScript, чтобы получить представление о том, как проходит процесс реализации.

Краткий список новых возможностей включает в себя:

  • Let (лексическая) и const (неизменяемая) привязки
  • Стрелочные функции (короткие анонимные функции) и лексическое this
  • Классы (синтаксический сахар поверх прототипов)
  • Улучшения объектных литералов (вычисляемые ключи, укороченные определения методов и т.д.)
  • Шаблонные строки
  • Промисы
  • Генераторы, итерируемые объекты, итераторы и for..of
  • Параметры функций по умолчанию и оператор rest
  • Spread-синтакис
  • Деструктуризация
  • Модульный синтаксис
  • Новые коллекции (Set, Map, WeakSet, WeakMap)
  • Прокси и Reflect
  • Тип данных Symbols
  • Типизированные массивы
  • Наследование классов
  • Оптимизация хвостовой рекурсии
  • Упрощённая поддержка Unicode
  • Двоичные и восьмеричные литералы

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

Некоторых может удивить, как могло такое количество новых возможностей проскочить мимо процесса стандартизации, во время которого был загублен ECMAScript 4. Хотелось бы отметить, что большинство наиболее агрессивных инноваций ECMAScript 4, таких, как пространства имён или опциональное типирование, были забыты и к ним больше не возвращались, в то время, как другие были переосмыслены с учётом возникших возражений. Работа над ECMAScript 2015 была очень тяжёлой и заняла почти шесть лет (и даже больше, учитывая время, необходимое на реализацию). Но сам факт того, что технический комитет ECMAScript смог справиться с таким трудным заданием, стал добрым знамением.

В 2020 году увидело свет небольшое обновление ECMAScript. Эта версия стала результатом нового процесса подготовки, принятого в TC-39. Все новые предложения должны пройти через четыре стадии. Предложение, достигшее четвёртой стадии, имеет все шансы быть включенным в следующую версию ECMAScript (однако комитет имеет право отложить его для более поздней версии). Таким образом, каждое предложение разрабатывается индивидуально (разумеется, с учётом его взаимодействия с другими предложениями), не тормозя разработку ECMAScript.

Если предложение готово к включению в стандарт, и достаточное количество других предложений достигло четвёртой стадии, в свет выходит новая версия ECMAScript.

Версия, выпущенная в 2020 году, была очень маленькой. Она включала в себя:

  • Оператор возведения в степень (**)
  • Array.prototype.includes
  • Несколько незначительных поправок (генераторы не могут быть использованы с new и т.д.)

И всё же несколько интересных предложений уже достигли четвёртой стадии в 2020 году. Что же готовит для нас ECMAScript?

Будущее близкое и не очень: ECMAScript 2020 и следующие версии

Самым важным предложением, достигшим четвёртой стадии, является async/await. это расширение синтаксиса для JavaScript, которое делает работу с промисами более приятной. Для примера рассмотрим код ECMAScript 2015:

И сравним его с кодом, в котором используется async/await:

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

  • Object.values и Object.entries
  • Выравнивание строк
  • Object.getOwnPropertyDescriptors
  • Разделители-запятые в параметрах функций

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

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

  • SIMD API
  • Асинхронные итераторы (async/await + итерация)
  • Стрелочные генераторы
  • Операции с 64-битными целыми числами
  • Области (изоляции состояний)
  • Общая память и Atomics

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

WebAssembly

Если вы не слышали о WebAssembly, вам стоит прочитать про него. Огромное количество библиотек и фреймворков, появившихся после выхода ECMAScript 5, а также общее развитие языка, сделали JavaScript интересной целью для других языков. Для больших кодовых структур функциональная совместимость является ключевой потребностью. Возьмите, к примеру, игры. Самым распространённым языком, на котором пишутся игры, является C++, благодаря чему их можно портировать на большое количество архитектур. Тем не менее портирование для браузера Windows или консольной игры считалось невыполнимой задачей. Однако это стало возможным благодаря стремительному развитию и небывалой эффективности сегодняшних виртуальных машин JavaScript. Именно для выполнения подобных задач на свет появились инструменты вроде Emscripten.

Быстро сориентировавшись в ситуации, Mozilla начала работу над тем, чтобы сделать JavaScript подходящей целью для компиляторов. Так на свет появился Asm.js — подмножество JavaScript, идеально подходящее в качестве подобной цели. Виртуальные машины JavaScript могут быть оптимизированы для распознавания этого подмножества и производства кода, намного лучшего, чем тот, который генерируют текущие виртуальные машины. Благодаря JavaScript браузеры медленно становятся новой целью для компиляторов.

И всё же существуют огромные ограничения, которые не в состоянии преодолеть даже Asm.js. В JavaScript необходимо внести такие изменения, которые расходятся с его текущим предназначением. Нужно что-то совершенно иное для того, чтобы сделать веб достойной целью для других языков программирования. И именно для этого предназначен WebAssembly — низкоуровневый язык программирования для веба. Любая программа может быть скомпилирована в WebAssembly при помощи подходящего компилятора и затем запущена в подходящей виртуальной машине (виртуальные машины JavaScript могут предоставить необходимый уровень семантики). Первые версии WebAssembly имеют стопроцентную совместимость со спецификацией Web.js. WebAssembly обещает не только более быстрое время загрузки (байт-код обрабатывается быстрее, чем текст), но и возможность оптимизации, недоступной в Asm.js. Представьте себе интернет с идеальной функциональной совместимостью между JavaScript и вашим языком программирования.

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

В настоящий момент dev-версии Chrome, Firefox и Microsoft Edge имеют начальную поддержку WebAssembly и способны проигрывать демо-приложения.

Использование JavaScript в Auth0

Мы в Auth0 очень плотно используем JavaScript, который является основным языком программирования везде, от Lock library до бэкендов. Его асинхронная натура и предельная простота для новых разработчиков являются ключевыми факторами нашего успеха. Мы с интересом наблюдаем за развитием языка и за его влиянием на всю экосистему.
Пройдите бесплатную регистрацию на Auth0 и ознакомьтесь с экосистемой, полностью написанной на JavaScript. Не беспокойтесь, у нас есть клиентские библиотеки для всех популярных фреймворков и платформ.

Классы и свойства JavaScript ES2015 часть 2

Классы, объекты и свойства

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

Свойства акссесора были введены одновременно с ECMAScript 5 ( ES5 ), но многие разработчики до сих пор не знают, что они существуют. Мы рассмотрим новый синтаксис классов, который позволяет проще работать с ними.

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

Свойства функций

Основной целью JavaScript prototype наследования является возможность наследования свойств функций ( свойств, которые указывают на какую-либо функцию ) от родительского объекта к дочернему. Значение свойства должно существовать непосредственно в дочернем объекте, поскольку значения специфичны для конкретного объекта. Кроме этого прохождение по цепочке прототипов для получения значений объекта является неэффективным. Но свойства функций отличаются от свойств значений. Очень редко реализации функций специфичны для конкретного объекта. Разделяя один и тот же объект между несколькими объектами, мы снижаем потребление памяти приложением JavaScript .

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

Нажмите здесь, чтобы загрузить код [this.js]

Свойство ‘ getFullName ‘ для обоих объектов, Person1 и Person2 , указывает на объект функции ‘ getFullName ‘. Повторно используя одну и ту же функцию для обоих объектов, мы потребляем меньший объем памяти, разделяя функцию между разными объектами.

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

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

Нажмите здесь, чтобы загрузить код [functions.js]

Обратите внимание, что функция ‘ getFullName ‘ определяется без использования ключевого слова function . С помощью синтаксиса класса ES2015 ключевое слово function опускается из определения объекта функции. Эта функция не будет прямым свойством объекта Person . Вместо этого она будет в JavaScript function prototype Person , от которого наследуется объект.

Свойства получателя / установщика

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

Нажмите здесь, чтобы загрузить код [accessors.js]

Статические свойства

JavaScript предоставляет конвенцию для определения статических свойств объектов. Классы ES2015 продолжают эту конвенцию через ключевое слово static :

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

Нажмите здесь, чтобы загрузить код [static.js]

Закрытые свойства

ES2015 до сих пор формально не поддерживает использование public , protected , и private модификаторов доступа для свойств объекта. В JavaScript все свойства являются public . Некоторые препроцессоры, такие как TypeScript , добавили поддержку транспиляции для public и private модификаторов доступа. С помощью использования выражения и private классов в JavaScript можно реализовать закрытые свойства:

Нажмите здесь, чтобы загрузить код [private.js]

Хотя эта конструкция работает, она имеет недостатки. private используются в JavaScript повсеместно, но это может снизить производительность приложений и привести к потреблению дополнительных ресурсов памяти. Создавать объемные закрытия, чтобы скрыть некоторые свойства, не рекомендуется. Кроме этого новый объект определения класса создается при каждом вызове функции-оболочки. Определение класса должно выполняться в функции-оболочке. Создание определения класса снова приведет к потреблению дополнительных ресурсов. Это ключевой момент, который вы должны помнить при использовании JavaScript object prototype .

JavaScript не C ++ , не Java и не C # . Он не поддерживает классическое наследование и в настоящее время не предназначен для того, чтобы « имитировать » характерные черты классического наследования, такие как модификаторы доступа. Добавление через подчеркивания или другие символы ( Angular.js использует $ ) префиксов private ( лучше назвать их внутренними ) свойств является общепринятой практикой, и приводит к достижению той же цели, не вызывая снижения производительности.

Заключение

Классы ES2015 улучшили синтаксис для определения свойств наследования объектов, свойств получателя / установщика. Они также четче выделяют различия между тем, какие свойства определяются в экземпляре объекта, какие наследуются, а какие рассматриваются, как статические. Классы ES2015 не меняют характер JavaScript prototype , но делают наследование более доступным для JavaScript разработчиков.

Данная публикация представляет собой перевод статьи « JavaScript ES2015 Classes and Properties (Part 2 of 2) » , подготовленной дружной командой проекта Интернет-технологии.ру

Стоит ли учить JavaScript: перспективы, ситуация на рынке труда, мнения экспертов

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

Экскурс в теорию: информация о JavaScript, сферах применения и особенностях языка

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

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

В число основных особенностей JS входят:

  • Динамическая типизация — тип данных определяется в момент присваивания значения константе или переменной.
  • Интерпретируемый язык — код приложения интерпретируется при обращении, не требуется предварительная компиляция.
  • Функции как объекты первого класса, то есть функции в JavaScript можно возвращать из функций, передавать в качестве параметров в другие функции, присваивать переменным.
  • Поддержка прототипного и объектно-ориентированного подхода.
  • Универсальность — все популярные браузеры поддерживают JavaScript.

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

Важная особенность JavaScript — развитая инфраструктура. Вокруг этого языка программирования сформировано многочисленное сообщество. Разработчикам доступны мощные инструменты, например:

  • Библиотеки и фреймворки для создания приложений (React, Vue).
  • Сборщики (Webpack, Gulp).
  • Вспомогательные библиотеки (Lodash, Underscore).
  • Генераторы статических сайтов (Gatsby.js, Next.js).

Сферы применения JavaScript

В первую очередь JavaScript широко используется во фронтенд-разработке. Этот язык вместе с HTML и CSS входит в базовый набор инструментов фронтендера. На JavaScript создаются приложения, которые исполняются в браузере на стороне клиента. Они обеспечивают интерактивность сайтов. Например, когда пользователь заполняет форму и нажимает кнопку «Подписаться», мгновенная реакция на это действие обычно обеспечивается кодом, написанным на JavaScript.

Сферы применения JavaScript не ограничиваются браузерами и веб-приложениями. С помощью этого языка решают такие задачи:

  • Разработка нативных приложений. Например, с помощью фреймворка React Native создаются приложения для Android и iOS.
  • Серверная разработка. Например, Node.js применяется для бэкенд-разработки. Об этом направлении в перспективе выйдет отдельная статья.
  • Разработка десктопных приложений. Например, JS применяется в офисных пакетах Microsoft и OpenOffice, в приложениях компании Adobe.
  • Программирование оборудования и бытовой техники, например, платёжных терминалов, телевизионных приставок.

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

Популярность, рейтинг и перспективы JavaScript

Как отмечалось выше, по состоянию на середину 2020 года JavaScript входит в число самых популярных языков программирования. JS занимает седьмое место в индексе TIOBE, который составляется на основе статистики поисковых запросов. Этот язык на данный момент популярнее, чем PHP, Swift, Objective-C, Ruby.

JavaScript занимает первое место по популярности в сообществе разработчиков на GitHub. Этот показатель рассчитывается по количеству репозиториев.

Как и PHP, JavaScript можно считать одним из способов быстро войти в разработку. JavaScript-программистов берут на работу веб-студии, которые есть как в крупнейших городах, так и в регионах.

О перспективах JavaScript подробно рассказывают эксперты в комментариях ниже. Стоит обратить внимание на два момента.

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

Второй момент: в настоящий момент растет популярность прогрессивных веб-приложений (PWA, progressive web apps). Эту технологию активно продвигает Google. Прогрессивные веб-приложения представляют собой гибрид сайта и мобильного приложения. В среднесрочной перспективе у PWA есть хорошие шансы отвоевать значительную долю рынка у нативных приложений.

Для разработки PWA применяется JavaScript. Например, сайты, созданные с помощью генератора Gatsby.js, поддерживают функциональность прогрессивного веб-приложения из коробки. Это ещё один плюс в пользу востребованности JS в ближайшей перспективе.

Сколько платят фронтендерам, или О зарплатах JavaScript-программистов

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

По данным trud.com на май 2020 года, средняя зарплата JavaScript-разработчика в России составляет 100 000 рублей. Больше всего вакансий на этом ресурсе с предложением зарплаты в диапазоне от 62 000 до 121 000 рублей (см. иллюстрацию). Чаще всего фронтенд-разработчики требуются в Москве, Санкт-Петербурге и Новосибирске.

По данным NewHR, вилка зарплат фронтенд-разработчиков уровня middle в июне 2020 года составляла от 160 000 до 190 000 рублей. По информации «Мой круг», медианная зарплата JavaScript-программиста в России во втором полугодии 2020 года составляла 85 000 рублей.

На сайте hh.ru по состоянию на конец июля 2020 года есть 81 вакансия для JavaScript-разработчиков в Казани (город взят для примера). Уровень зарплаты варьируется от 20 000 до 165 000 рублей.

Информацию по своему региону можно получить самостоятельно с помощью сайтов поиска работы.

Перспективы JavaScript: взгляд экспертов

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

Сергей Рубанов: спрос на рынке труда JavaScript-разработчиков сильно превышает предложение

По вашему опыту, почему стоит изучать JS?

Несмотря на то, что JS имеет свои странности, он невероятно прост для изучения и терпим к ошибкам. Экосистема языка хорошо развита, так что если вы чувствуете в себе силы, то сможете легко настроить более строгие правила для написания кода, используя различные инструменты, позволяющие избегать популярных ошибок или даже добавить статическую типизацию. В данный момент JavaScript — единственный высокоуровневый динамический язык, доступный практически везде, в том числе (и в первую очередь) на веб-страницах. Это позволяет выучить один язык, частично переиспользовать готовые наработки для клиента, сервера, в роботостроении, для интернета вещей, даже для машинного обучения. А ещё у JavaScript огромное, невероятно классное и самое открытое комьюнити.

Какие перспективы у этого языка программирования по сравнению с другими языками?

JavaScript — один из самых распространенных языков в мире. В индексе TIOBE в данный момент он занимает 7 место (и индекс растет), а по количеству репозиториев на GitHub и популярности по результатам опроса Stack Overflow он находится на первом месте и является вторым желаемым языком после Python. Пакетный менеджер npm является самым крупным пакетным менеджером из всех существующих. Все это говорит о том, что перспективы у языка великолепные.

Будет ли он востребован в будущем?

Только недавно стали появляться технологии, которые в чём-то смогут заменить JavaScript в браузерах, но понадобится ещё очень долгое время, прежде чем эти технологии достигнут достаточного уровня развития и научатся всему тому, что может JavaScript. К тому же на сервере и во встраиваемых системах у JavaScript есть много альтернатив, но и там он имеет свою нишу. Многие компании вкладывали и вкладывают огромные деньги в развитие движков, в которых JavaScript исполняется, что позволяет делать язык всё эффективнее и не терять своей актуальности.

Каковы перспективы JS-разработчика на рынке труда?

Спрос на рынке труда JavaScript-разработчиков сильно превышает предложение, отсюда же и хорошие зарплаты. Компании ищут разработчиков любого уровня, в том числе начинающих.

Почему новичку стоит обратить внимание на этот язык?

количество информации, которую можно найти в интернете;

развитая экосистема в виде огромнейшего количества библиотек и инструментов для разработки;

очень хорошее комьюнити;

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

высокий спрос на рынке труда;

Сергей Рубанов, опытный разработчик и лидер сообществ. Приглашённый эксперт TC39 (комитет, который занимается разработкой языка JavaScript), участник WebAssembly Community Group, член команды Babel, соорганизатор BeerJS Moscow, WebAssembly Moscow, ведущий канала Juliarderity (совместно с Романом Дворновым).

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

По вашему опыту, почему стоит изучать JS?

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

На это была простая причина: клиенты стали более требовательными к скорости работы и отзывчивости интерфейсов. Поставив лайк, посетители хотят сразу видеть +1, а не ждать полсекунды, пока сервер ответит. Нажал кнопку, моментально получил реакцию. И это можно сделать, если избавиться от сетевых задержек между сервером и клиентом — перенести исполняемый код, который дает результат максимально близко к клиенту, то есть в его браузер.

А в браузерах обосновался старичок JavaScript. Причем если лет 5-10 назад было стыдно говорить, что ты программируешь на JavaScript, так как его было сложно считать удобным и производительным языком, то после выхода ES6 удобство резко возросло и продолжает расти благодаря работе комитета TC39 (куда входят куча спецов из больших компаний), который развивает синтаксис языка.

Производительность языка постоянно увеличивается. Но благодаря большому комьюнити, интересу больших интернет гигантов к языку, неуклонно растет количество инструментария, которые сильно облегчает разработку. Например, ESlint (проверка стиля кода), Prettier — автоформатирование кода, Babel — для транспилинга кода и напиcания всяких AST-трансформеров, JIT-компиляторов.

Но что не может не радовать, так это TypeScript, который позволяет писать статически типизированный код (Flowtype проиграл для меня войну). Статическая типизация позволяет писать более стабильный и качественный код, дает плюшки автоподстановки в IDE. В общем, корпоративный сектор все больше задач может доверить миру JavaScript. Современный джаваскрипт с классами, декораторами, интерфейсами, типизацией все больше и больше становится похожим на Java в хорошем смысле этого слова. А если учесть, что JavaScript сейчас работает как на клиенте (в браузере), так и на сервере (NodeJS), то это это для бизнеса открывает возможность писать изоморфные приложения.

Будет ли этот язык востребован в будущем?

За пару лет популярность JS должна будет только расти. Ведь столько еще чудовищных интерфейсов вокруг, столько мертвых страниц, сгенерированных сервером. JS будет теснить PHP и Ruby.

Так или иначе JavaScript еще будет востребован как минимум лет 10, дальше прогнозировать сложно.

Что угрожает JavaScript/TypeScript:

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

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

В любом случаем надо постоянно учиться и развиваться, чтоб соответствовать текущему времени. Но, к бабке не ходи, лет через 10 надо точно будет чему-то сильно переучиваться.

Каковы перспективы разработчика JS на рынке труда?

Сейчас есть некий перекос в сторону фронтенд-разработчиков, которые производят wow-эффект на клиентов. К примеру, на Украине сейчас активно ищутся React/Vue/Angular разработчики. И нередко зарплата таких фронтенд-специалистов с опытом 1-2 года по зарплате соизмерима со среднестатистическим Java-бэкендером с опытом 6-8 лет. Нужны легкие деньги после универа?! Вперед в JS!

Почему новичку стоит обратить внимание на JS?

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

Павел Черторогов, архитектор информационных систем, GraphQL-гуру.

Роман Дворнов: JavaScript вряд ли куда-либо денется в ближайшие годы

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

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

Кстати, о новом. JavaScript — один из немногих языков с таким немалым возрастом (был создан в декабре 1995-го), который настолько динамично развивается сегодня. Формально все началось в 2015 году, когда вышла новая редакция ES2015 (или ES6) и было решено выпускать новую редакцию каждый год, хотя на самом деле всё началось задолго до этого. Не каждый год случаются значительные изменения, но изменения происходят и чувствуется темп. Можно следить за работой TC39 (комитет работающий над спецификацией языка), участвовать в обсуждениях предложений, вносить свои предложения и так далее – процесс открыт, и это здорово. К тому же, сегодня имплементаторы внедряют новые фичи накануне принятия новой редакции спецификации языка, а не несколько лет спустя, как это было раньше.

Низкий порог входа всегда был предметом споров: с одной стороны, вовлекается больше людей, с другой — их уровень как специалистов невысок. Это, плюс часто неглубокое изучение, обычно и создает негативное отношение к языку. Чтобы использовать JavaScript эффективно, его нужно изучать полностью, и дополнительно множество смежных областей, а особенно Computer Science, как это делают в случае с другими языками. Все больше задач с применением JavaScript не уступают по сложности задачам решаемым с другими языками.

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

Во-вторых, необходимость шарить логику между клиентом и сервером, Server Side Rendering и прочее, укрепляет позиции JavaScript на серверной стороне. В-третьих, тулинг для JavaScript, как и для клиентского веб-стека, по большей части написан на JavaScript.

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

Роман Дворнов, эксперт в области фронтенд-разработки, ведущий канала Juliarderity (совместно с Сергеем Рубановым). Профиль на GitHub.

Андрей Оконечников: будем ли мы писать JS через несколько лет — неизвестно, но 99% что мы будем продолжать компилировать в JS

По вашему опыту, почему стоит изучать JS? Какие перспективы у этого языка программирования по сравнению с другими языками?

Несмотря на интересные альтернативы, такие как ReasonML, Kotlin и уже существующие языки, которые компилируются в JS, такие как ClojureScript и Elm, это никак особенно не влияет на всё растущую популярность JS. Причина для того, на мой взгляд, в низком пороге входа и огромной экосистеме (npm). На JS написано несколько миллионов опенсорс модулей, которые можно установить за считанные секунды. Плюс возможность открыть консоль разработчика в браузере и начать писать код.

Развитие распределенных сред разработки, которые работают напрямую из браузера, например CodeSandbox, ещё более уменьшают порог входа для новичков. Инструменты разработки становятся лучше и лучше, позволяя использовать JS в больших командах.

Одновременно с этим, растущая производительность JS runtimes, например V8, делает использование этого языка все более приемлемым на платформах вне веб-браузеров.

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

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

Будет ли JS востребован в будущем?

JavaScript никуда не денется в ближайшее время, хотим мы того или нет. На этом языке уже сейчас написано огромное количество кода, и количество это будет только увеличиваться. И даже если появится более современный язык, веб-браузеры все равно будут вынуждены поддерживать JS. Так устроен web — вечная совместимость. Будем ли мы писать JS через несколько лет — неизвестно, но 99% что мы будем продолжать компилировать в JS.

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

Сейчас перспективы как никогда лучше. Особенно связанные с фронтендом. Веб превращается в платформу для по-настоящему сложных приложений, и рынок просто не способен удовлетворить потребность компаний. Но JS не единственный фактор. Умение писать CSS и доступный HTML важны сегодня как никогда. Рынок JS разработчиков наполняется в основном из backend-разработчиков, переквалифицирующихся во frontend. Если вы видите себя во frontend, я бы очень рекомендовал обратить внимание на основы дизайна, user experience, HTML + CSS и, конечно же, JavaScript.

Если вы дизайнер и уже умеете писать разметку и CSS, я бы так же советовал начать изучать JavaScript. В будущем граница между JS и CSS-программистами будет исчезать, так как очень сложно сделать хороший user experience в Web без использования обоих языков.

Андрей Оконечников, фронтенд-разработчик и UI-дизайнер родом из Ярославля, живущий в Вене, Австрия. Более 10 лет он придумывает и разрабатывает пользовательские интерфейсы, используя современные веб-технологии. До этого он работал дизайнером веб-сайтов и пользовательских интерфейсов. Комбинация опыта дизайнера и разработчика помогает ему лучше понимать проблемы пользователей и находить оригинальные решения в пользовательских интерфейсах.

Андрей работал с такими компаниями, как Yandex, JetBrains, Feedly, Netlify и многими другими. Он основатель консалтинг-компании component-driven.io, специализирующейся на дизайн системах и сложных веб-интерфейсах, и создатель macOS приложения цветовой пипетки для разработчиков и дизайнеров ColorSnapper.

Александр Казаченко: на одного подходящего кандидата приходится 10 или более неподходящих, это печалит

По вашему опыту, почему стоит изучать JS?

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

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

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

И на сервере JS тоже имеет свою нишу в виде Nodejs.

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

Но если посмотреть не с точки зрения прагматизма, а с точки зрения энтузиазма, то в этом смысле JS тоже очень привлекателен.

Сейчас существует множество языков, транспилирующихся в JS (TypeScript, CoffeeScript, Kotlin и так далее), много фреймворков и библиотек разного уровня абстрактности, что позволяет разрабатывать на JS так, как нравится именно вам.

Какие перспективы у самого языка программирования в сравнении с другими? Будет ли он востребован в будущем?

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

Соответственно, можно считать, что в ближайшие лет 10 JS не только не умрет, но и будет активно развиваться.

На какое направление при изучении JS обратить больше внимания — frontend или backend?

Изначально JS применялся сугубо для frontend’а, соответственно и развился он больше в эту сторону. Но это не имеет никакого значения, при выборе направления — frontend или backend. Более значимым в этом выборе будет то, чем интересно заниматься именно вам. Так как язык один и тот же, разница только в окружении.

Какие перспективы у JS-разработчика в работе? Почему новичку стоит обратить внимание на этот язык программирования?

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

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

За последние 3 года я прособеседовал не менее 200 человек, и на одного подходящего кандидата приходится 10 или более неподходящих, это печалит.

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

Стоит ли браться за JavaScript: итоги

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

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

Примечание: мнение экспертов может не совпадать с мнением администрации и сотрудников Хекслета.

Топ-пост этого месяца:  Создание списка похожих материалов в WordPress (с миниатюрами) при помощи плагина Related Posts для
Добавить комментарий