Реализовать обратный вызов с помощью функции, которая не принимает обратный вызов?

#javascript

#javascript

Вопрос:

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

Комментарии:

1. У вас есть пример, чтобы прояснить ваш вопрос? JavaScript — это язык общего назначения, в нем возможно многое.

2. Почему вы не можете просто вызвать две функции одну за другой?

3. Я хочу, чтобы функция B запускалась по завершении функции A — функция A отправляет запрос на удаленный сервер, а функция B зависит от изменений, которые функция A внесла в глобальную переменную.

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

Ответ №1:

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

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

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

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

Итак…

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

Комментарии:

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

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

3. Я согласен; обратные вызовы удобны и в синхронных средах.

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

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

Ответ №2:

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

Допустим, вы начинаете с этой функции:

 function originalFunctionName()
{
 // do something
}
  

вы можете присвоить существующей функции новое имя:

 var backupOfOriginal = originalFunction;
  

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

 var originalFunctionName = function()
{
  // do something else
  // call backup function
  backupOfOriginal();
}
  

тогда, если вы вызываете исходное имя функции:

 originalFunctionName();
  

весь код будет выполнен.

Ответ №3:

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

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

Ответ №4:

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

Если исходная функция является вызовом Ajax, и вы пытаетесь заменить один из ее обработчиков, это другая проблема, хотя вы могли бы использовать jQuery $.when(original).then(function () { … }) в зависимости от ваших реальных потребностей.