Получение лучшего понимания функций обратного вызова в JavaScript

163

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

var myCallBackExample = {
    myFirstFunction : function( param1, param2, callback ) {
        // Do something with param1 and param2.
        if ( arguments.length == 3 ) {
            // Execute callback function.
            // What is the "best" way to do this?
        }
    },
    mySecondFunction : function() {
        myFirstFunction( false, true, function() {
            // When this anonymous function is called, execute it.
        });
    }
};

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


источник
Правильно в каком смысле? Обычно обратные вызовы используются для обработчиков событий - в частности, Ajax-вызовов, которые являются асинхронными, - в основном это вещи, в которых вы не знаете, когда (или если) произойдет повторное восстановление.
Клет
2
кстати, аргументы похожи на массив, но не на массив, поэтому вы не можете сделать аргумент. длина, но вы можете преобразовать его в массив, используя метод среза ...
Пол
1
@paul, хотя вы и правы, что argumentsэто не массив, вы все равно можете ссылаться на его длину как arguments.length... попробуйте. Это свойство относится к числу фактически переданных аргументов, а не обязательно к числу параметров в сигнатуре функции.
hotshot309

Ответы:

132

Вы можете просто сказать

callback();

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

callback.call( newValueForThis);

Внутри функции thisбудет все, что newValueForThisесть.

krosenvold
источник
91

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

if (callback && typeof(callback) === "function") {
    // execute the callback, passing parameters as necessary
    callback();
}

Многие библиотеки (jQuery, dojo и т. Д.) Используют аналогичный шаблон для своих асинхронных функций, а также node.js для всех асинхронных функций (nodejs обычно передается errorи dataдля обратного вызова). Просмотр их исходного кода поможет!

arunjitsingh
источник
Почему вы приводите callbackк строке, а затем проверяете ее тип? Повысит ли это производительность? Это все равно что проверить тип, проверить, возвращает ли преобразованное логическое значение true, а затем снова проверить его тип и проверить его на соответствие строке. Не могли бы вы объяснить, почему?
headacheCoder
Мне любопытно, почему вам нужно первое утверждение для обратного вызова ... это проверить нулевое или неопределенное? Не typeof(callback)достиг бы этого для вас? typeof(null) === "Object",typeof("undefined") === "undefined"
PJH
1
Короткое замыкание И. Если обратного вызова не существует, не беспокойтесь о вычислении его типа. Хотя ты прав. Это не нужно с typeof (), но я сделаю jsperf и посмотрю, стоит ли короткое замыкание.
arunjitsingh
@headacheCoder - callbackне приводится к строке, ее тип проверяется, чтобы узнать, является ли она функцией, прежде чем она будет вызвана. Код предположительно принимает callbackв качестве аргумента и не уверен, что аргумент имеет вызываемый тип - или, возможно, аргументы имеют различные типы в попытке обеспечить форму полиморфизма, где код может по-разному реагировать на разные typeofаргументы.
LeeGee
34

Есть 3 основных варианта выполнения функции:

var callback = function(x, y) {
    // "this" may be different depending how you call the function
    alert(this);
};
  1. обратный вызов (аргумент_1, аргумент_2);
  2. callback.call (some_object, аргумент_1, аргумент_2);
  3. callback.apply (some_object, [аргумент_1, аргумент_2]);

Выбор метода зависит от того:

  1. У вас есть аргументы, хранящиеся в массиве или в виде отдельных переменных.
  2. Вы хотите вызвать эту функцию в контексте некоторого объекта. В этом случае использование ключевого слова this в этом обратном вызове будет ссылаться на объект, переданный в качестве аргумента в call () или apply (). Если вы не хотите передавать контекст объекта, используйте null или undefined. В последнем случае глобальный объект будет использоваться для «этого».

Документы для Function.call , Function.apply

Ionuț G. Stan
источник
6

Обратные вызовы - это сигналы, а «new» - создание экземпляров объектов.

В этом случае было бы еще более уместно выполнить просто «callback ();» чем "return new callback ()", потому что вы все равно ничего не делаете с возвращаемым значением.

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

annakata
источник
6

правильная реализация будет:

if( callback ) callback();

это делает параметр обратного вызова необязательным.

faeb187
источник
Что если аргумент обратного вызова не является функцией?
Яки Кляйн
2

Ты можешь использовать:

if (callback && typeof(callback) === "function") {
    callback();
}

Приведенный ниже пример является немного более полным:

function mySandwich(param1, param2, callback) {
  alert('Started eating my sandwich.\n\nIt has: ' + param1 + ', ' + param2);
  var sandwich = {
      toppings: [param1, param2]
    },
    madeCorrectly = (typeof(param1) === "string" && typeof(param2) === "string") ? true : false;
  if (callback && typeof(callback) === "function") {
    callback.apply(sandwich, [madeCorrectly]);
  }
}

mySandwich('ham', 'cheese', function(correct) {
  if (correct) {
    alert("Finished eating my " + this.toppings[0] + " and " + this.toppings[1] + " sandwich.");
  } else {
    alert("Gross!  Why would I eat a " + this.toppings[0] + " and " + this.toppings[1] + " sandwich?");
  }
});

Хасан Юсеф
источник
1

Вот базовый пример, который объясняет callback()функцию в JavaScript:

var x = 0;

function testCallBack(param1, param2, callback) {
  alert('param1= ' + param1 + ', param2= ' + param2 + ' X=' + x);
  if (callback && typeof(callback) === "function") {
    x += 1;
    alert("Calla Back x= " + x);
    x += 1;
    callback();
  }
}

testCallBack('ham', 'cheese', function() {
  alert("Function X= " + x);
});

JSFiddle

БЕРГУИГА Мохамед Амин
источник
1

function checkCallback(cb) {
  if (cb || cb != '') {
    if (typeof window[cb] === 'undefined') alert('Callback function not found.');
    else window[cb].call(this, Arg1, Arg2);
  }
}

Аамир Африди
источник