Erstellen Sie einen benutzerdefinierten Rückruf in JavaScript

321

Alles was ich tun muss, ist eine Rückruffunktion auszuführen, wenn meine aktuelle Funktionsausführung endet.

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

Ein Verbraucher für diese Funktion sollte folgendermaßen aussehen:

object.LoadData(success);

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

Wie implementiere ich das?

Amgad Fahmi
quelle
3
object.LoadData(success)Anruf muss nach function success definiert sein. Andernfalls erhalten Sie eine Fehlermeldung, dass die Funktion nicht definiert ist.
J. Bruni

Antworten:

573

Tatsächlich funktioniert Ihr Code so wie er ist. Deklarieren Sie einfach Ihren Rückruf als Argument, und Sie können ihn direkt mit dem Argumentnamen aufrufen.

Die Grundlagen

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);

Das wird anrufen doSomething, das wird anrufen foo, das wird alarmieren "Zeug geht hierher".

Beachten Sie, dass es sehr wichtig ist , um die Funktion zu übergeben Referenz ( foo), anstatt die Funktion aufrufen und das Ergebnis vorbei ( foo()). In Ihrer Frage machen Sie es richtig, aber es lohnt sich nur darauf hinzuweisen, weil es ein häufiger Fehler ist.

Fortgeschrittenere Sachen

Manchmal möchten Sie den Rückruf aufrufen, damit ein bestimmter Wert für angezeigt wird this. Mit der JavaScript- callFunktion können Sie dies ganz einfach tun :

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`

Sie können auch Argumente übergeben:

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`

Manchmal ist es nützlich, die Argumente, die Sie dem Rückruf geben möchten, als Array und nicht einzeln zu übergeben. Sie können dies verwenden apply, um:

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`
TJ Crowder
quelle
Ich weiß, dass es funktionieren wird, wenn ich keine Parameter wie das von Ihnen geschriebene Beispiel habe, aber wenn ich versuche, eine Funktion mit Parametern zu übergeben, wird eine Ausnahme
ausgelöst
@TiTaN: Das ist seltsam, es ist nichts Besonderes, Parameter an den Rückruf zu übergeben. Die Rückrufreferenz, die Sie an Ihre Funktion übergeben, ist eine Funktionsreferenz wie jede andere, mit der Sie alle normalen Dinge tun können.
TJ Crowder
4
@jeder, der geantwortet hat: Ich denke, TiTaNs Problem ist, dass er nicht weiß, wie man eine Funktion, die Argumente erfordert, an einen Rückruf übergibt, der keine Argumente übergibt. Denken Sie nach setTimeout(). Die Antwort ist, den Rückruf in einen Abschluss zu doSomething(function(){foo('this','should','work')})
packen
Jemand zeigt TiTaN auf einen Thread (vorzugsweise auf SO), der das oben genannte Problem diskutiert. Mein Such-Fu ist heute schwach.
Slebetman
1
@Webwoman - Das hängt von Ihrem Anwendungsfall ab. Sie können es als Argument übergeben oder in ein Einstellungsobjekt / Optionsobjekt oder eine von mehreren anderen Optionen aufnehmen.
TJ Crowder
77

Es wird empfohlen, sicherzustellen, dass der Rückruf eine tatsächliche Funktion ist, bevor Sie versuchen, ihn auszuführen:

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

  callback();
}
Donald A Nummer Jr.
quelle
21
if(typeof callback == "function")wird das gleiche Ergebnis haben.
Reactgular
22
Ja, aber wenn es keinen Rückruf gibt, warum sollte man sich die Mühe machen, ihn zu tippen? Das ist der Punkt von callback && ...
theonlygusti
61

Mein 2 Cent. Dasselbe nur anders...

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


    function dosomething(damsg, callback){
        alert(damsg);
        if(typeof callback == "function") 
        callback();
    }
</script>
K. Kilian Lindberg
quelle
7
Ich liebe dieses Snippet, ich habe danach gesucht
vimal1083
10
function loadData(callback) {

    //execute other requirement

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

loadData(function(){

   //execute callback

});
Arun Bahal
quelle
6
Bitte überlegen Sie, Ihren Beitrag zu bearbeiten, um weitere Erklärungen darüber hinzuzufügen, was Ihr Code tut und warum er das Problem löst. Eine Antwort, die meistens nur Code enthält (auch wenn sie funktioniert), hilft dem OP normalerweise nicht, ihr Problem zu verstehen. In diesem Fall handelt es sich jedoch um eine sehr alte Frage, bei der bereits hoch angesehene Antworten veröffentlicht wurden. Es lohnt sich möglicherweise nicht, diese Frage zu beantworten, wenn es neuere Fragen gibt, die mehr Aufmerksamkeit erfordern könnten.
SuperBiasedMan
1
Ich mag diese Antwort, die str8 vorwärts demonstriert, was die Leute sehen wollen.
Aft3rL1f3
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 !");
});

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

Ergebnis ist:

hello world !
Eyad Farra
quelle
4

Wenn Sie eine Funktion ausführen möchten, wenn etwas erledigt ist. Eine gute Lösung besteht darin, Ereignisse anzuhören. Zum Beispiel werde ich Dispatchereine DispatcherEventKlasse mit ES6 implementieren , dann:

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')

Dispatcher:

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)
    }))
  }
}

Viel Spaß beim Codieren!

p / s: Mein Code fehlt, um einige Fehlerausnahmen zu behandeln

hien
quelle
1
function LoadData(callback) 
{
    alert('the data have been loaded');
    callback(loadedData, currentObject);
}
Thomas Bonini
quelle
1

Wenn wir die Rückruffunktion aufrufen, können wir sie wie folgt verwenden:

consumingFunction(callbackFunctionName)

Beispiel:

// Callback function only know the action,
// but don't know what's 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

Dies ist das Codepend mit vollständigem Beispiel.

Eric Tan
quelle
1

Einige der Antworten sind zwar richtig, aber möglicherweise etwas schwierig zu verstehen. Hier ist ein Beispiel für Laien:

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);

Der Rückruf bedeutet, dass "Jake" immer zu den Benutzern hinzugefügt wird, bevor die Liste der Benutzer mit angezeigt wird console.log .

Quelle (YouTube)

Dan Bray
quelle
0

Versuchen:

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

Funktionen sind in JavaScript erstklassig ; Sie können sie einfach weitergeben.

K Prime
quelle