Ihads.ru

Все про недвижимость
1 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Что такое callback-функция — Аргумент другой функции

Что такое callback-функция — Аргумент другой функции

Что такое callback-функции в JavaScript и для чего они нужны?

Callback (в переводе с английского call — вызов, back — обратный) или функция обратного вызова.

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

И прежде чем начать говорить о callback-функциях, рассмотрим пример с классическими функциями .

Последовательная и асинхронная работа функций

Есть две функции: first() и second() . Сначала вызывается first , затем second .

Но первая функция выполняется с задержкой .

В итоге сначала мы получаем результат работы 2-ой функции second() . А через некоторое время — результат работы 1-ой функции first() .

Пример 1.1

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

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

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

Что такое callback-функция?

Теперь можно перейти к ответу на вопрос: что такое callback-функция?

callback-функция — это функция, которая должна быть выполнена после того , как другая функция завершит свое выполнение .

Шаблон callback-функции

Рассмотрим пример: в функцию в качестве аргумента передается другая — callback-функция, то есть ТА, которая будет выполняться после выполнения основной функции.

Пример 2.1

1. Есть функция learnJS с двумя аргументами:

— 1-ый аргумент — в данном случае какое-либо строковое значение;
— 2-ой аргумент — это другая (callback) функция.

2. Функция process передается в качестве аргумента функции learnJS и, соответственно, функция process выполняется после выполнения функции learnJS .

Стоит обратить внимание : когда функция №2 передается в качестве аргумента в функцию №1 : learnJS(‘JavaScript’, process); то в круглых скобках указывается только имя функции №2 — без круглых скобок .

Читайте так же:
Счетчик меркурий 100 ампер прямого включения

Так как функция №2 не вызывается, а именно передается . А вызываться она будет уже внутри функции №1 тогда, когда до нее дойдет JS-интерпретатор.

Как вариант, в качестве аргумента функции learnJS может использоваться анонимная функция (функция без имени).

Пример 2.2

Итак, использование callback-функций позволяет соблюдать последовательность выполнения функций.

callback-функции на практике

callback-функции на практике используются довольно часто, например, при запросах к серверу. А серверное программирование на Node.js во многом основано на работе с callback-функциями.

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

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

Под капотом: циклы событий, стек вызовов и асинхронный код в JavaScript

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

Движок JS состоит из стека, кучи и очереди задач.

Это структура, похожая по строению на массив, отслеживающая исполняемые функции.

В данном случае функция m() обращается к функциям a() и b() . Во время исполнения программы адрес функции m помещается в стек вызова. Чтобы лучше понять концепцию адресации памяти, стоит изучить принципы работы операционной системы.

Прежде чем обработать код функции, движок JS помещает её адрес в стек вызова. На самом низком уровне существуют регистры EAX, EBX, ECX, ESP, EIP. Они используются центральным процессором для временного хранения переменных и исполнения загруженных в память программ. EAX и EBX используются для вычислений, ECX обрабатывает счётчики (например в цикле for). ESP (указатель стека) содержит текущий адрес стека, EIP (указатель инструкции) — адрес исполняемой программы.

Читайте так же:
Постановление правительства 261 счетчики

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

Сначала загружается наша программа, затем стек вызова, ESP и EIP. Точка входа программы — функция m() , поэтому EIP указывает на соответствующий адрес в памяти. Когда процессор начинает исполнять программу, он обращается к EIP и получает точку старта. В нашем случае он начинает с адреса 10 и исполняет m() .

В Ассемблере это выражение call m . Когда происходит вызов функции, система обращается к соответствующему адресу и начинает исполнение команд оттуда. Выполнив функцию, система продолжает исполнять код с того места, с которого был осуществлён вызов. Стек вызова содержит адрес возврата точки исполнения. При каждом вызове функции текущее значение EIP помещается в этот стек. В нашем примере при вызове a() память будет выглядеть следующим образом:

Когда работа функции a завершается, адрес (7) выталкивается из стека в EIP, и исполнение программы продолжается с этого адреса.

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

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

Эта строка создаёт объект класса Animal , размещает его в куче и возвращает адрес переменной lion . Поскольку объекты в куче не упорядочены, менеджер памяти ОС должен контролировать распределение адресов таким образом, чтобы не допускать появления неиспользуемого пространства.

Очередь задач

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

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

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

Полезные книги и статьи по теме (на английском языке):

  • “Assembly Language: Function Calls” by Jennifer Rexford; by Bertalan Miklos; .
Читайте так же:
Счетчик подписчиков как у ютуберов

Параметры функции

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

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

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

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

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

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

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

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

Действие можно увидеть здесь. Если вы откроете свой инструмент разработки, то вы увидите ошибку, которая говорит, что «undefined is not a function» (или что-то подобное), которое показывается после выполнения alert сообщения.

Чтобы сделать callback-функцию необязательной, мы может сделать так:

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

IDE

Хотя вы можете набирать и запускать JS-программу с помощью блокнота, IDE упрощает отладку кода и обеспечивает поддержку систем ALM (Application Lifecycle Management). Вот 3 лучших редактора IDE / исходного кода:

  • WebStorm: WebStorm обеспечивает интеллектуальную помощь и автозавершение кода, рефакторинг для CSS, TypeScript, JS. Вы можете проверить свою функциональность и устранить неполадки с помощью встроенного отладчика, ориентированного как на Node.js, так и на клиентский код. Используйте 30-дневную пробную версию, чтобы ознакомиться с продуктом, прежде чем покупать его.
  • Visual Studio Code: буквально нет языка, который не поддерживает VS Code. Это бесплатная, удобная для разработчиков кроссплатформенная среда IDE, которая предлагает такие функции, как встроенная интеграция с Git, интеллектуальное завершение кода, отладка кода из самого редактора и многое другое. Он очень расширяемый.
  • Atom: Atom — очень популярная IDE от GitHub. Он обеспечивает интеллектуальное завершение кода на основе контекста, простую навигацию по коду, полный набор диагностических инструментов для понимания и отладки кода и многие другие функции. Это бесплатно и с открытым исходным кодом, и вы можете добавить немного веселья в код, используя предустановленные темы и стили.
Читайте так же:
Калибровка счетчиков частиц lasair

Онлайн-среда разработки Javascript:

AWS Cloud9 : помимо JS, AWS Cloud9 также поддерживает разработку для C, C ++, Perl, Python, Node.js и т. Д. Оно полностью написано на JS, а серверная часть находится на Node.js. Это онлайн-среда с открытым исходным кодом, и для получения доступа требуется учетная запись AWS. Некоторые функции включают подсветку синтаксиса, поддержку npm и основных команд UNIX, одновременное редактирование, анализ языка в реальном времени и настраиваемые привязки клавиш.

Псевдомассив аргументов "arguments"

В JavaScript нет «перегрузки» функций

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

А уже внутри она может посмотреть, с чем вызвана и по-разному отработать.

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

выведем список всех аргументов:

В старом стандарте JavaScript псевдо-массив arguments и переменные-параметры ссылаются на одни и те же значения.

В результате изменения arguments влияют на параметры и наоборот.

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

arguments – это не массив

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

Такие объекты иногда называют «коллекциями» или «псевдомассивами».

Напишите функцию sum(…), которая возвращает сумму всех своих аргументов:

Адская пирамида вызовов

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

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

  1. Мы загружаем 1.js. Продолжаем, если нет ошибок.
  2. Мы загружаем 2.js. Продолжаем, если нет ошибок.
  3. Мы загружаем 3.js. Продолжаем, если нет ошибок. И так далее (*).
Читайте так же:
Поменять счетчик до июля

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

Иногда это называют «адом колбэков» или «адской пирамидой колбэков».

ад колбэков

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

Такой подход к написанию кода конечно же не приветствуется.

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

Заметили? Этот код делает всё то же самое, но вложенность отсутствует,а все потому что все действия вынесены в отдельные функции.

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

Кроме того, все функции step* одноразовые, и созданы лишь только, чтобы избавиться от так называемой «адской пирамиды вызовов». Никто не будет их вызывать где-либо ещё. Таким образом, мы, кроме всего прочего, засоряем и пространство имён.

Нужно найти способ получше.

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

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

голоса
Рейтинг статьи
Ссылка на основную публикацию
Adblock
detector