language-agnostic settimeout 자바 - 콜백 함수 란 무엇입니까?





10 Answers

불투명 한 정의

콜백 함수는 다른 코드에 제공하는 함수로 해당 코드에서 호출 할 수 있습니다.

고안된 예

왜 이걸하고 싶니? 호출해야하는 서비스가 있다고 가정 해 봅시다. 서비스가 즉시 반환되면 다음을 수행하십시오.

  1. 불러라
  2. 결과 기다리기
  3. 결과가 나오면 계속하십시오.

예를 들어, 서비스가 factorial 함수라고 가정합니다. 당신이 5! 의 가치를 원할 때 5! factorial(5) 호출하면 다음 단계가 수행됩니다.

  1. 현재 실행 위치가 저장됩니다 (스택에서는 중요하지 않음).

  2. 실행은 계승으로 넘어 간다.

  3. factorial 완료되면 결과를 얻을 수있는 곳으로 결과를 넣습니다.

  4. 실행은 그것이 있었던 곳으로 되돌아 온다 [1]

factorial 은 정말 오랜 시간이 걸렸습니다. 왜냐하면 당신은 거대한 숫자를주고 있기 때문에 일부 슈퍼 컴퓨터 클러스터에서 실행해야하기 때문입니다. 결과를 반환하는 데 5 분이 걸릴 것이라고 기대한다고 가정 해 봅시다. 너는 할 수 있었다 :

  1. 잠을자는 동안 야간에 디자인을 유지하고 프로그램을 실행하여 반 시간 동안 화면을 보지 않아야합니다.

  2. factorial 이 그 일을하는 동안 다른 일을하도록 프로그램을 설계하십시오.

두 번째 옵션을 선택하면 콜백이 작동합니다.

엔드 - 투 - 엔드 디자인

콜백 패턴을 악용하려면 다음과 같은 방법으로 factorial 을 호출 할 수 있어야합니다.

factorial(really_big_number, what_to_do_with_the_result)

두 번째 매개 변수, what_to_do_with_the_resultfactorial 이 반환하기 전에 결과로 호출 할 것이라는 희망에서 factorial 따라 보내는 함수입니다.

예, 이것은 factorial 이 콜백을 지원하도록 작성되어야 함을 의미합니다.

이제 콜백에 매개 변수를 전달할 수 있기를 원한다고 가정 해 보겠습니다. 이제는 할 수 없습니다. 왜냐하면 당신이 그것을 부르지 않을 것이기 때문에, factorial 이 있습니다. 따라서 factorial 은 매개 변수를 전달할 수 있도록 작성해야하며 호출 할 때 콜백으로 전달합니다. 다음과 같이 보일 수 있습니다.

factorial (number, callback, params)
{
    result = number!   // i can make up operators in my pseudocode
    callback (result, params)
}

factorial 에서이 패턴을 허용하므로 콜백은 다음과 같이 보일 수 있습니다.

logIt (number, logger)
{
    logger.log(number)
}

factorial 대한 당신의 부름은

factorial(42, logIt, logger)

logIt 에서 무엇인가를 반환하려면 어떻게해야합니까? 왜냐하면 factorial 은 그것에 관심을 기울이지 않기 때문입니다.

왜 콜 래 factorial 반환하는 것을 factorial 반환 할 수 없습니까?

비 차단으로 만들기

factorial 이 끝나면 실행은 콜백으로 전달되기 때문에 호출자에게 아무 것도 반환하지 않아야합니다. 그리고 이상적으로는 다른 스레드 / 프로세스 / 머신에서 작업을 시작하고 즉시 돌아와 다음과 같이 계속 진행할 수 있습니다.

factorial(param_1, param_2, ...)
{
    new factorial_worker_task(param_1, param_2, ...);
    return;
}

이것은 이제 "비동기 호출"입니다. 즉, 호출 할 때 즉시 반환되지만 실제로 아직 수행하지 않았습니다. 따라서 여러분은 그것을 확인하고 완료 될 때 그 결과를 얻는 메커니즘이 필요하며, 프로그램은 그 과정에서 더 복잡해집니다.

그런데 factorial_worker_task 는이 패턴을 사용하여 콜백을 비동기 적으로 시작하고 즉시 반환 할 수 있습니다.

그럼 어떻게 하시겠습니까?

대답은 콜백 패턴 내에 있어야한다는 것입니다. 언제든지 쓰기를 원할 때마다

a = f()
g(a)

그리고 f 를 비동기 적으로 호출하려면, 대신에

f(g)

여기서 g 는 콜백으로 전달됩니다.

이것은 근본적으로 프로그램의 흐름 토폴로지를 변경하고 익숙해 져갑니다.

프로그래밍 언어는 함수를 즉석에서 생성 할 수있는 방법을 제공함으로써 많은 도움이 될 수 있습니다. 위의 코드에서 함수 gprint (2*a+1) 만큼 작을 수 있습니다. 이 언어를 별도의 함수로 정의하고 완전히 불필요한 이름과 서명으로 정의해야한다면이 패턴을 많이 사용하면 인생이 불편해질 것입니다.

반면에 언어를 사용하여 람다를 만들 수 있다면 훨씬 좋은 모습을 보입니다. 그러면 뭔가를 쓰게 될 것입니다.

f( func(a) { print(2*a+1); })

그것은 훨씬 더 좋네요.

콜백 전달 방법

factorial 콜백 함수를 어떻게 전달합니까? 글쎄, 당신은 여러 가지 방법으로 그것을 할 수 있습니다.

  1. 호출 된 함수가 동일한 프로세스에서 실행중인 경우 함수 포인터를 전달할 수 있습니다

  2. 아니면 fn name --> fn ptr 사전을 유지하고 싶을 수도 있습니다.이 경우 이름을 전달할 수 있습니다

  3. 어쩌면 당신의 언어로 람다 (lambda)처럼 가능한 장소에서 함수를 정의 할 수 있습니다! 내부적으로 어떤 종류의 객체를 생성하고 포인터를 전달하지만 그것에 대해 걱정할 필요가 없습니다.

  4. 아마도 여러분이 호출하는 함수는 완전히 별개의 시스템에서 실행되고 있으며 HTTP와 같은 네트워크 프로토콜을 사용하여 호출 할 것입니다. 콜백을 HTTP 호출 가능 함수로 노출하고 URL을 전달할 수 있습니다.

당신은 아이디어를 얻습니다.

콜백의 최근 상승

우리가 입력 한 웹 시대에 우리가 호출하는 서비스는 종종 네트워크를 통해 이루어집니다. 우리는 종종 이러한 서비스를 제어하지 못합니다. 즉, 우리는 서비스를 작성하지 않았고, 서비스를 유지하지 않으며, 서비스가 작동하는지 또는 서비스를 수행하는지 확인할 수 없습니다.

그러나 우리는 이러한 서비스가 응답하기를 기다리는 동안 프로그램을 차단할 수 없습니다. 이 사실을 알고 있으므로 서비스 제공 업체는 종종 콜백 패턴을 사용하여 API를 디자인합니다.

JavaScript는 람다 (lambd)와 클로저 (closure)와 같은 콜백 (callback)을 매우 잘 지원합니다. 자바 스크립트 세계에는 브라우저뿐만 아니라 서버에서도 많은 활동이 있습니다. 모바일 용으로 개발 된 JavaScript 플랫폼도 있습니다.

앞으로 더 많은 사람들이 비동기 코드를 작성하게 될 것이며, 이러한 이해는 필수적입니다.

스크립트 비동기 프로그래밍

콜백 함수 란 무엇입니까?




평신도 응답은 특정 이벤트가 발생하거나 일부 코드가 처리 된 후 사용자 또는 브라우저가 호출하지 않는 기능이라는 것입니다.




나는이 "콜백"전문 용어가 많은 곳에서 실수로 사용되었다고 생각합니다. 내 정의는 다음과 같습니다.

콜백 함수는 누군가에게 전달하여 어느 시점에 호출하게하는 함수입니다.

사람들은 위키 정의의 첫 번째 문장을 읽은 것 같습니다.

콜백은 다른 코드에 인수로 전달되는 실행 가능 코드 또는 실행 가능한 코드에 대한 참조입니다.

다양한 API를 사용하여 여러 가지 나쁜 예를 살펴 보았습니다. 많은 사람들이 함수 포인터 (실행 코드에 대한 참조) 또는 익명 함수 (실행 코드의 일부) "콜백"으로 이름을 지정하는 경향이 있습니다. 단지 함수 인 경우 왜 다른 이름을 사용해야합니까?

사실 위키 정의의 두 번째 문장 만이 콜백 함수와 일반 함수의 차이점을 보여줍니다.

이렇게하면 하위 레벨 소프트웨어 계층이 상위 수준 계층에 정의 된 서브 루틴 (또는 함수)을 호출 할 수 있습니다.

차이점은 함수를 전달할 대상과 전달 된 함수가 호출되는 방법입니다. 함수를 정의하고 다른 함수에 전달하고 해당 함수 본문에서 직접 호출 한 경우 콜백이라고하지 마십시오. 정의에 따르면 전달 된 함수는 "하위 수준"함수에 의해 호출됩니다.

나는 사람들이 애매한 맥락에서이 단어를 사용하는 것을 멈출 수 있기를 바랄 뿐이다.




간단하게 유지합시다. 콜백 기능이란 무엇입니까?

비유와 유추의 예

나는 비서가있다. 매일 나는 그녀에게 다음과 같이 요청한다 : (i) 우체국에서 회사의 보내는 메일을 내려 놓는다. 그녀가 그 일을 마친 후에 : (ii) 내가 그 스티커 노트 중 하나에 대해 그녀에게 쓴 작업.

자, 스티커 메모의 작업은 무엇입니까? 작업은 날마다 다릅니다.

이 특별한 날에, 나는 그녀에게 어떤 서류를 인쇄하라고 요구한다. 그래서 나는 스티커 메모에 그걸 적었고, 나는 그녀가 게시해야하는 보내는 메일과 함께 책상에 고정시켰다.

요약하자면:

  1. 첫째로, 그녀는 우편물에서 내려야하고
  2. 그 일이 끝난 직후 , 그녀는 몇 가지 서류를 인쇄해야합니다.

콜백 기능은 두 번째 작업 : 해당 문서를 인쇄하는 것입니다. 우편물이 내려진 후에도 끝났기 때문에, 또한 그녀에게 가장 필요한 우편물과 함께 그녀에게 문서를 인쇄하라고 말하는 스티커 메모가 주어지기 때문에.

이제 이것을 프로그래밍 어휘로 묶어 보겠습니다.

  • 이 경우 메서드 이름은 : DropOffMail입니다.
  • 콜백 함수는 PrintOffDocuments입니다. PrintOffDocuments는 비서가 DropOffMail이 실행 된 후에 만 ​​수행하기를 원하기 때문에 콜백 함수입니다.
  • 그래서 나는 "DropOffMail"메소드에 대한 "인자"로서의 PrintOffDocuments를 전달할 것이다. 이것은 중요한 포인트이다.

그것이 전부입니다. 아무것도 더. 나는 당신을 위해 그것을 정리했으면하고, 그렇지 않다면, 코멘트를 게시하고 명확히하기 위해 최선을 다할 것입니다.




콜백 함수는 기존 함수 / 메서드에 지정하는 함수로, 작업이 완료 될 때 호출되거나 추가 처리가 필요합니다.

Javascript에서, 또는 특히 jQuery에서, 예를 들어, 애니메이션이 끝날 때 콜백 인자를 지정할 수 있습니다.

PHP에서 preg_replace_callback() 함수를 사용하면 정규 표현식이 일치 할 때 호출되는 함수를 제공하고 인수로 일치하는 문자열을 전달할 수 있습니다.




이미지보기 :)

주 프로그램은 콜백 함수 이름을 가진 라이브러리 함수 (시스템 레벨 함수 일 수도 있음)를 호출합니다. 이 콜백 함수는 여러 가지 방법으로 구현 될 수 있습니다. 주 프로그램은 요구 사항에 따라 하나의 콜백을 선택합니다.

마지막으로 라이브러리 함수는 실행 중에 콜백 함수를 호출합니다.




sort() 의 구현에서 어떤 점에서 사용될 수있는 함수 포인터를 인수로 받아 들일 수있는 sort(int *arraytobesorted,void (*algorithmchosen)(void)) 함수가 있다고 가정합니다. 그런 다음 여기에서 함수 포인터 algorithmchosen 의해 처리되는 코드를 콜백 함수 라고 합니다 .

그리고 장점은 다음과 같은 알고리즘을 선택할 수 있다는 것입니다.

  1.    algorithmchosen = bubblesort
  2.    algorithmchosen = heapsort
  3.    algorithmchosen = mergesort   ...

말하자면 프로토 타입으로 구현 된 것입니다.

  1.   `void bubblesort(void)`
  2.   `void heapsort(void)`
  3.   `void mergesort(void)`   ...

이것은 객체 지향 프로그래밍에서 다형성을 달성하는 데 사용되는 개념입니다.




"컴퓨터 프로그래밍에서 콜백은 다른 코드에 인수로 전달되는 실행 가능한 코드 또는 실행 가능한 코드에 대한 참조입니다. 이것은 하위 레벨 소프트웨어 레이어가 상위 레벨 레이어에 정의 된 서브 루틴 (또는 함수)을 호출 할 수있게합니다. "- Wikipedia

함수 포인터를 사용하여 C에서 콜백

C에서는 콜백 함수 포인터를 사용하여 구현됩니다. 함수 포인터 - 이름에서 알 수 있듯이 함수에 대한 포인터입니다.

예를 들어, int (* ptrFunc) ();

여기서 ptrFunc는 인수를 취하지 않고 정수를 반환하는 함수에 대한 포인터입니다. 괄호를 넣는 것을 잊지 마십시오. 그렇지 않으면 컴파일러는 ptrFunc가 아무 것도 취하지 않고 정수에 대한 포인터를 반환하는 일반 함수 이름이라고 가정합니다.

다음은 함수 포인터를 보여주는 코드입니다.

#include<stdio.h>
int func(int, int);
int main(void)
{
    int result1,result2;
    /* declaring a pointer to a function which takes
       two int arguments and returns an integer as result */
    int (*ptrFunc)(int,int);

    /* assigning ptrFunc to func's address */                    
    ptrFunc=func;

    /* calling func() through explicit dereference */
    result1 = (*ptrFunc)(10,20);

    /* calling func() through implicit dereference */        
    result2 = ptrFunc(10,20);            
    printf("result1 = %d result2 = %d\n",result1,result2);
    return 0;
}

int func(int x, int y)
{
    return x+y;
}

이제 우리는 함수 포인터를 사용하여 C에서 콜백 개념을 이해하려고 노력합니다.

전체 프로그램에는 callback.c, reg_callback.h 및 reg_callback.c의 세 파일이 있습니다.

/* callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}

int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                        
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                          
    printf("back inside main program\n");
    return 0;
}

/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);


/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                               
}

이 프로그램을 실행하면 출력은

이것은 주 프로그램 내에서 my_callback 내부의 register_callback 내부에서 함수 콜백을 시연하는 프로그램입니다.

상위 계층 함수는 하위 계층 함수를 일반 호출로 호출하고 콜백 메커니즘은 하위 계층 함수가 콜백 함수에 대한 포인터를 통해 상위 계층 함수를 호출하도록 허용합니다.

인터페이스를 사용한 Java의 콜백

Java는 함수 포인터 개념을 가지고 있지 않습니다. 인터페이스 메커니즘을 통해 콜백 메커니즘을 구현합니다. 여기서는 함수 포인터 대신 호출 수신자가 작업을 완료 할 때 호출 될 메소드가있는 인터페이스를 선언합니다

예를 통해 설명해 드리겠습니다.

콜백 인터페이스

public interface Callback
{
    public void notify(Result result);
}

호출자 또는 상위 레벨 클래스

public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}

피 호출자 또는 하위 계층 기능

public Class Callee {
Callback cb;
Callee(Callback cb){
this.cb = cb;
}

doAsynctask(){
//do the long running task
//get the result
cb.notify(result);//after the task is completed, notify the caller
}
}

EventListener 패턴을 사용하는 콜백

  • 목록 항목

이 패턴은 특정 작업이 완료된 관찰자 / 수신기의 수를 0에서 n까지 알리는 데 사용됩니다

  • 목록 항목

콜백 메커니즘과 EventListener / Observer 메커니즘의 차이점은 콜백에서 호출 수신자가 단일 호출자에게 알리는 반면 Eventlisener / Observer에서 호출 수신자는 해당 이벤트에 관심이있는 모든 사용자에게 알릴 수 있다는 것입니다. 알림은 해당 호출의 다른 부분으로 이동할 수 있습니다. 작업을 트리거하지 않은 응용 프로그램)

예를 통해 설명하겠습니다.

이벤트 인터페이스

public interface Events {

public void clickEvent();
public void longClickEvent();
}

클래스 위젯

package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}

클래스 버튼

public class Button extends Widget{
private String mButtonText;
public Button (){
} 
public String getButtonText() {
return mButtonText;
}
public void setButtonText(String buttonText) {
this.mButtonText = buttonText;
}
}

클래스 체크 박스

public class CheckBox extends Widget{
private boolean checked;
public CheckBox() {
checked = false;
}
public boolean isChecked(){
return (checked == true);
}
public void setCheck(boolean checked){
this.checked = checked;
}
}

활동 클래스

com.som_itsolutions.training.java.exampleeventlistener 패키지;

public class Activity implements Widget.OnClickEventListener
{
    public Button mButton;
    public CheckBox mCheckBox;
    private static Activity mActivityHandler;
    public static Activity getActivityHandle(){
        return mActivityHandler;
    }
    public Activity ()
    {
        mActivityHandler = this;
        mButton = new Button();
        mButton.setOnClickEventListner(this);
        mCheckBox = new CheckBox();
        mCheckBox.setOnClickEventListner(this);
        } 
    public void onClick (Widget source)
    {
        if(source == mButton){
            mButton.setButtonText("Thank you for clicking me...");
            System.out.println(((Button) mButton).getButtonText());
        }
        if(source == mCheckBox){
            if(mCheckBox.isChecked()==false){
                mCheckBox.setCheck(true);
                System.out.println("The checkbox is checked...");
            }
            else{
                mCheckBox.setCheck(false);
                System.out.println("The checkbox is not checked...");
            }       
        }
    }
    public void doSomeWork(Widget source){
        source.clickEvent();
    }   
}

기타 수업

public class OtherClass implements Widget.OnClickEventListener{
Button mButton;
public OtherClass(){
mButton = Activity.getActivityHandle().mButton;
mButton.setOnClickEventListner(this);//interested in the click event                        //of the button
}
@Override
public void onClick(Widget source) {
if(source == mButton){
System.out.println("Other Class has also received the event notification...");
}
}

메인 클래스

public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Activity a = new Activity();
OtherClass o = new OtherClass();
a.doSomeWork(a.mButton);
a.doSomeWork(a.mCheckBox);
}
}

위의 코드에서 알 수 있듯이 기본적으로 응용 프로그램에서 발생할 수있는 모든 이벤트를 나열하는 이벤트라는 인터페이스가 있습니다. Widget 클래스는 Button, Checkbox와 같은 모든 UI 구성 요소의 기본 클래스입니다. 이러한 UI 구성 요소는 실제로 프레임 워크 코드에서 이벤트를 수신하는 객체입니다. 위젯 클래스는 Events 인터페이스를 구현하며 OnClickEventListener 및 OnLongClickEventListener라는 두 개의 중첩 인터페이스도 제공합니다.

이 두 인터페이스는 Button이나 Checkbox와 같은 위젯 파생 UI 구성 요소에서 발생할 수있는 이벤트를 수신합니다. 따라서이 예를 Java Interface를 사용하는 이전 Callback 예제와 비교하면이 두 인터페이스가 Callback 인터페이스로 작동합니다. 따라서 상위 레벨 코드 (Here Activity)는이 두 인터페이스를 구현합니다. 이벤트가 위젯에 발생할 때마다 상위 레벨 코드 (또는 상위 레벨 코드에 구현 된이 인터페이스의 메소드, 여기서는 Activity)가 호출됩니다.

이제 Callback과 EventListener 패턴의 기본적인 차이점을 설명하겠습니다. Callback을 사용한다고 언급했듯이, Callee는 한 명의 발신자에게만 알릴 수 있습니다. 그러나 EventListener 패턴의 경우 응용 프로그램의 다른 부분이나 클래스가 Button이나 Checkbox에서 발생할 수있는 이벤트를 등록 할 수 있습니다. 이런 종류의 클래스의 예는 OtherClass입니다. OtherClass의 코드를 보면, Activity에 정의 된 Button에서 발생할 수있는 ClickEvent에 대한 리스너로 자신을 등록한 것을 알 수 있습니다. 재미있는 부분은 Activity (호출자) 외에도 Button에서 click 이벤트가 발생할 때마다이 OtherClass에 알림이 전송된다는 것입니다.




고차 함수라고도하는 콜백 함수는 다른 함수에 매개 변수로 전달되는 함수이며 콜백 함수는 부모 함수 내에서 호출 (또는 실행)됩니다.

$("#button_1").click(function() {
  alert("button 1 Clicked");
});

여기에서는 click 메소드에 매개 변수로 함수를 전달합니다. 그리고 click 메소드는 우리가 전달한 콜백 함수를 호출 (또는 실행)합니다.




콜백 함수는 특정 함수 또는 객체에 (참조 또는 포인터로) 전달하는 함수입니다. 이 함수 또는 객체는 언제든지이 함수를 임의의 목적을 위해 나중에 여러 번 다시 호출합니다.

  • 과제의 종료를 알리는 것
  • 두 항목 간의 비교 요청 (예 : qsort ())
  • 프로세스 진행보고
  • 이벤트 알리기
  • 사물의 인스턴스화를 위임하다.
  • 지역 그림 그리기

...

따라서 콜백을 다른 함수 또는 태스크의 끝에서 호출되는 함수로 설명하는 것은 지나치게 단순화됩니다 (일반적인 사용 사례 일지라도).




Related