Создание пользовательского обратного вызова в JavaScript

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

function LoadData() 
{
    alert('The data has been loaded');
    //Call my callback with parameters. For example,
    //callback(loadedData , currentObject);
}

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

object.LoadData(success);

function success(loadedData , currentObject) 
{
  //Todo: some action here 
}

Как это реализовать?

Ответ 1

Собственно, ваш код будет работать так же, как есть, просто объявите свой обратный вызов как аргумент, и вы можете вызвать его напрямую, используя имя аргумента.

Основы

function doSomething(callback) {
    // ...

    // Call the callback
    callback('stuff', 'goes', 'here');
}

function foo(a, b, c) {
    // I'm the callback
    alert(a + " " + b + " " + c);
}

doSomething(foo);

Это вызовет doSomething, который вызовет foo, который будет предупреждать, что "материал идет здесь".

Обратите внимание, что очень важно передать ссылку на функцию (foo) вместо вызова функции и передачи ее результата (foo()). В вашем вопросе вы делаете это правильно, но это просто стоит указать, потому что это общая ошибка.

Более продвинутый материал

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

function Thing(name) {
    this.name = name;
}
Thing.prototype.doSomething = function(callback) {
    // Call our callback, but using our own instance as the context
    callback.call(this);
}

function foo() {
    alert(this.name);
}

var t = new Thing('Joe');
t.doSomething(foo);  // Alerts "Joe" via `foo`

Вы также можете передать аргументы:

function Thing(name) {
    this.name = name;
}
Thing.prototype.doSomething = function(callback, salutation) {
    // Call our callback, but using our own instance as the context
    callback.call(this, salutation);
}

function foo(salutation) {
    alert(salutation + " " + this.name);
}

var t = new Thing('Joe');
t.doSomething(foo, 'Hi');  // Alerts "Hi Joe" via `foo`

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

function Thing(name) {
    this.name = name;
}
Thing.prototype.doSomething = function(callback) {
    // Call our callback, but using our own instance as the context
    callback.apply(this, ['Hi', 3, 2, 1]);
}

function foo(salutation, three, two, one) {
    alert(salutation + " " + this.name + " - " + three + " " + two + " " + one);
}

var t = new Thing('Joe');
t.doSomething(foo);  // Alerts "Hi Joe - 3 2 1" via `foo`

Ответ 2

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

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

  callback();
}

Ответ 3

Мои 2 цента. То же самое, но другое...

<script>
    dosomething("blaha", function(){
        alert("Yay just like jQuery callbacks!");
    });


    function dosomething(damsg, callback){
        alert(damsg);
        if(typeof callback == "function") 
        callback();
    }
</script>

Ответ 4

function loadData(callback) {

    //execute other requirement

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

loadData(function(){

   //execute callback

});

Ответ 5

   function callback(e){
      return e;
   }
    var MyClass = {
       method: function(args, callback){
          console.log(args);
          if(typeof callback == "function")
          callback();
       }    
    }

==============================================

MyClass.method("hello",function(){
    console.log("world !");
});

==============================================

Результат:

hello world !

Ответ 6

function LoadData(callback) 
{
    alert('the data have been loaded');
    callback(loadedData, currentObject);
}

Ответ 7

При вызове функции обратного вызова мы можем использовать его, как показано ниже:

consumingFunction(callbackFunctionName)

Пример:

// Callback function only know the action,
// but don't know what the data.
function callbackFunction(unknown) {
  console.log(unknown);
}

// This is a consuming function.
function getInfo(thenCallback) {
  // When we define the function we only know the data but not
  // the action. The action will be deferred until excecuting.
  var info = 'I know now';
  if (typeof thenCallback === 'function') {
    thenCallback(info);    
  }
}

// Start.
getInfo(callbackFunction); // I know now

Это Codepend с полным примером.

Ответ 8

Try:

function LoadData (callback)
{
    // ... Process whatever data
    callback (loadedData, currentObject);
}

Функции являются первоклассными в JavaScript; вы можете просто передать их.

Ответ 9

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

var users = ["Sam", "Ellie", "Bernie"];

function addUser(username, callback)
{
    setTimeout(function()
    {
        users.push(username);
        callback();
    }, 200);
}

function getUsers()
{
    setTimeout(function()
    {
        console.log(users);
    }, 100);
}

addUser("Jake", getUsers);

Средство обратного вызова "Jake" всегда добавляется к пользователям перед отображением списка пользователей с помощью console.log.

Источник (YouTube)

Ответ 10

Если вы хотите выполнить функцию, когда что-то сделано. Одним из хороших решений является прослушивание событий. Например, я реализую Dispatcher, класс DispatcherEvent с ES6, а затем:

let Notification = new Dispatcher()
Notification.on('Load data success', loadSuccessCallback)

const loadSuccessCallback = (data) =>{
   ...
}
//trigger a event whenever you got data by
Notification.dispatch('Load data success')

Диспетчер:

class Dispatcher{
  constructor(){
    this.events = {}
  }

  dispatch(eventName, data){
    const event = this.events[eventName]
    if(event){
      event.fire(data)
    }
  }

  //start listen event
  on(eventName, callback){
    let event = this.events[eventName]
    if(!event){
      event = new DispatcherEvent(eventName)
      this.events[eventName] = event
    }
    event.registerCallback(callback)
  }

  //stop listen event
  off(eventName, callback){
    const event = this.events[eventName]
    if(event){
      delete this.events[eventName]
    }
  }
}

DispatcherEvent:

class DispatcherEvent{
  constructor(eventName){
    this.eventName = eventName
    this.callbacks = []
  }

  registerCallback(callback){
    this.callbacks.push(callback)
  }

  fire(data){
    this.callbacks.forEach((callback=>{
      callback(data)
    }))
  }
}

Счастливое кодирование!

p/s: мой код отсутствует, обрабатывает некоторые исключения ошибок