Получение лучшего понимания функций обратного вызова в 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есть.


91

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

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

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


Почему вы приводите 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


6

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

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

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


6

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

if( callback ) callback();

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


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

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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.