Ознайомлення з функціями зворотного дзвінка в 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, якщо я повертаю новий зворотний виклик (), він працює і виконує анонімну функцію, але це не здається правильним підходом до мене.


Правильно в якому сенсі? Зазвичай зворотні виклики використовуються для обробників подій - найчастіше дзвінки Ajax, які є асинхронними - в основному це те, де ви не знаєте, коли (або якщо) настане відповідь.
— клент

2
до речі аргументи такі як масив, але не масив, тому ви не можете зробити argument.length, але ви можете перетворити його в масив, використовуючи метод зрізу ...
— paul

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, а потім ще раз перевірка його типу та тестування на рядок ... Чи можете ви пояснити, чому?
— головний

Мені цікаво, чому вам потрібно перше твердження про зворотний виклик ... це перевірити нульове чи невизначене? Ви б цього не 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, argument_1, argument_2);
  3. callback.apply (some_object, [argument_1, argument_2]);

Вибраний спосіб залежить від того:

  1. У вас аргументи зберігаються в масиві або як окремі змінні.
  2. Ви хочете викликати цю функцію в контексті якогось об'єкта. У цьому випадку використання ключового слова "це" у цьому зворотному дзвінку посилатиметься на об'єкт, переданий як аргумент у call (), або застосувати (). Якщо ви не хочете передавати контекст об'єкта, використовуйте null або undefined. В останньому випадку глобальний об’єкт буде використовуватися для "цього".

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


6

Відкликання дзвінків - це сигнали, а "нове" - про створення об'єктів.

У цьому випадку було б ще доцільніше виконати просто "callback ();" ніж "повернути новий зворотний виклик ()", оскільки ви все одно нічого не робите зі значенням повернення.

(І аргумент argument.length == 3 дійсно незграбний, fwiw, краще перевірити, чи існує парам зворотного виклику і є функцією.)


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.