在JavaScript中创建自定义回调


322

我需要做的就是在当前函数执行结束时执行一个回调函数。

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 
}

我该如何实施?


3
object.LoadData(success)调用必须 function success定义之后。否则,您将收到一条错误消息,告诉您该函数未定义。
J. Bruni

Answers:


574

实际上,您的代码将按原样工作,只需将回调声明为参数即可,您可以使用参数名称直接调用它。

基础

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`

我知道如果没有像您编写的示例那样的任何参数,它将起作用,但是当我尝试传递带有参数的函数时,它将引发异常并告诉我该函数未定义
Amgad Fahmi,2010年

@TiTaN:奇怪,将参数传递给回调没有什么特别的。传递给函数的回调引用是一个函数引用,就像其他函数引用一样,您可以使用它执行所有正常的操作。
TJ Crowder '02

4
@回答的每个人:我认为TiTaN的问题是他不知道如何将需要参数的函数传递给不传递任何参数的回调。想想setTimeout()。答案是将回调包装在闭包中:doSomething(function(){foo('this','should','work')})
slebetman 2010年

有人将TiTaN指向讨论上述问题的线程(最好是SO),今天我的搜索能力很弱。
slebetman '02

1
@Webwoman-这取决于您的用例。您可以将其作为参数传递,也可以将其包含在某种设置/选项对象或其他几个选项中。
TJ Crowder

77

优良作法是在尝试执行之前确保回调是实际函数:

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

  callback();
}

21
if(typeof callback == "function")将具有相同的结果。
Reactgular 2013年

22
是的,但是如果没有回调,为什么还要打扰呢?那就是callback && ...
theonlygusti 2014年

61

我的2美分。相同但不同...

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


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

7
我喜欢这个
摘要

10
function loadData(callback) {

    //execute other requirement

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

loadData(function(){

   //execute callback

});

6
请考虑编辑您的帖子,以添加更多有关代码功能以及为什么它可以解决问题的解释。通常仅包含代码(即使它可以正常工作)的答案通常不会帮助OP理解他们的问题。但是,在这种情况下,这是一个非常老的问题,已经发布了备受推崇的答案,当有新的问题需要更多关注时,回答这个问题可能就不值得了。
SuperBiasedMan

1
我喜欢这个答案,它展现了人们想要看到的东西的str8向前展示。
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 !");
});

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

结果是:

hello world !

4

如果您想在完成某件事后执行一个函数。一个好的解决方案之一就是监听事件。例如,我将用ES6 实现Dispatcher一个DispatcherEvent类,然后:

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:我的代码丢失处理一些错误异常


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

1

当调用回调函数时,我们可以像下面这样使用它:

consumingFunction(callbackFunctionName)

例:

// 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

这是带有完整示例的Codepend


1

有些答案虽然正确,但可能难以理解。这是一个外行的例子:

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)


0

尝试:

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

函数是JavaScript中的第一类; 您可以将它们传递出去。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.