Tạo một cuộc gọi lại tùy chỉnh trong JavaScript


322

Tất cả những gì tôi cần làm là thực thi chức năng gọi lại khi việc thực hiện chức năng hiện tại của tôi kết thúc.

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

Một người tiêu dùng cho chức năng này nên như thế này:

object.LoadData(success);

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

Làm thế nào để tôi thực hiện điều này?


3
object.LoadData(success)cuộc gọi phải sau khi function success được xác định. Nếu không, bạn sẽ gặp lỗi cho bạn biết chức năng không được xác định.
J. Bruni

Câu trả lời:


574

Trên thực tế, mã của bạn sẽ hoạt động khá nhiều, chỉ cần khai báo cuộc gọi lại của bạn như là một đối số và bạn có thể gọi nó trực tiếp bằng tên đối số.

Những thứ cơ bản

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

Điều đó sẽ gọi doSomething, sẽ gọi foo, sẽ cảnh báo "công cụ ở đây".

Lưu ý rằng việc truyền tham chiếu hàm ( foo) là rất quan trọng , thay vì gọi hàm và truyền kết quả của nó ( foo()). Trong câu hỏi của bạn, bạn làm điều đó đúng, nhưng nó chỉ đáng để chỉ ra vì đó là một lỗi phổ biến.

Những thứ cao cấp hơn

Đôi khi bạn muốn gọi lại để nó thấy một giá trị cụ thể cho this. Bạn có thể dễ dàng làm điều đó với callchức năng JavaScript :

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`

Bạn cũng có thể truyền đối số:

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`

Đôi khi nó hữu ích để vượt qua các đối số bạn muốn đưa ra cuộc gọi lại dưới dạng một mảng, thay vì riêng lẻ. Bạn có thể sử dụng applyđể làm điều đó:

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`

Tôi biết nó sẽ hoạt động nếu tôi không có bất kỳ tham số nào như ví dụ bạn đã viết nhưng khi tôi cố gắng truyền một hàm với các tham số thì nó sẽ đưa ra một ngoại lệ và cho tôi biết chức năng này không được xác định
Amgad Fahmi

@TiTaN: Thật lạ, không có gì đặc biệt khi truyền tham số vào cuộc gọi lại. Tham chiếu gọi lại mà bạn chuyển vào hàm của bạn là một tham chiếu hàm giống như bất kỳ tham chiếu nào khác, bạn có thể thực hiện tất cả những điều bình thường với nó.
TJ Crowder

4
@everyone người trả lời: Tôi nghĩ vấn đề của TiTaN là anh ta không biết cách truyền một hàm yêu cầu đối số vào một cuộc gọi lại mà không vượt qua bất kỳ đối số nào. Hãy suy nghĩ setTimeout(). Câu trả lời là kết thúc cuộc gọi lại trong một lần đóng cửa:doSomething(function(){foo('this','should','work')})
slebetman

Ai đó trỏ TiTaN đến một chủ đề (tốt nhất là trên SO) thảo luận về vấn đề trên, tìm kiếm của tôi ngày nay rất yếu.
slebetman

1
@Webdess - Nó phụ thuộc vào trường hợp sử dụng của bạn. Bạn có thể chuyển nó dưới dạng đối số hoặc đưa nó vào một số loại đối tượng cài đặt / tùy chọn hoặc bất kỳ tùy chọn nào khác.
TJ Crowder

77

Đó là một thực tế tốt để đảm bảo gọi lại là một chức năng thực tế trước khi cố gắng thực hiện nó:

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

  callback();
}

21
if(typeof callback == "function")sẽ có kết quả tương tự.
Phản ứng

22
Có, nhưng nếu không có cuộc gọi lại, tại sao lại phải gõ nó? Đó là điểm của callback && ...
theonlygusti 24/12/14

61

2 xu của tôi. Giống nhau nhưng khác nhau ...

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


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

7
Tôi yêu đoạn trích này, tôi đã tìm kiếm nó
vimal1083

10
function loadData(callback) {

    //execute other requirement

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

loadData(function(){

   //execute callback

});

6
Vui lòng xem xét chỉnh sửa bài đăng của bạn để thêm giải thích về những gì mã của bạn làm và lý do tại sao nó sẽ giải quyết vấn đề. Một câu trả lời chủ yếu chỉ chứa mã (ngay cả khi nó hoạt động) thường không giúp OP hiểu vấn đề của họ. Tuy nhiên, trong trường hợp này, đây là một câu hỏi rất cũ với các câu trả lời được đánh giá cao đã được đăng, nó có thể không đáng để bạn trả lời câu hỏi này khi có những câu hỏi mới hơn có thể được chú ý nhiều hơn.
SuperBiasedMan

1
Tôi thích câu trả lời này trình diễn về phía trước str8 về những gì mọi người muốn xem.
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 !");
});

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

Kết quả là:

hello world !

4

Nếu bạn muốn thực thi một chức năng khi một cái gì đó được thực hiện. Một trong những giải pháp tốt là lắng nghe các sự kiện. Ví dụ: tôi sẽ triển khai một Dispatcher, một DispatcherEventlớp với ES6, sau đó:

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

Điều phối:

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

Chúc mừng mã hóa!

p / s: Mã của tôi bị thiếu xử lý một số trường hợp ngoại lệ lỗi


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

1

Khi gọi hàm gọi lại, chúng ta có thể sử dụng nó như dưới đây:

consumingFunction(callbackFunctionName)

Thí dụ:

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

Đây là Codepend với ví dụ đầy đủ.


1

Một số câu trả lời, trong khi chính xác có thể hơi khó hiểu. Đây là một ví dụ trong các điều khoản của giáo dân:

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

Gọi lại có nghĩa là, "Jake" luôn được thêm vào người dùng trước khi hiển thị danh sách người dùng console.log.

Nguồn (YouTube)


0

Thử:

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

Các hàm là lớp đầu tiên trong JavaScript ; bạn chỉ có thể vượt qua chúng xung quanh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.