>  기사  >  웹 프론트엔드  >  javascript_기초지식의 콜백함수가 무엇인지 알려주세요

javascript_기초지식의 콜백함수가 무엇인지 알려주세요

WBOY
WBOY원래의
2016-05-16 16:37:241280검색

 함수도 객체이다

콜백 함수를 이해하려면 먼저 함수의 규칙을 명확히 이해해야 합니다. JavaScript에서 함수는 이상하지만 실제로는 객체입니다. 정확하게 말하면 함수는 Function() 생성자를 사용하여 생성된 Function 객체입니다. Function 개체에는 함수의 JavaScript 코드가 포함된 문자열이 포함되어 있습니다. C나 Java에서 왔다면 이상하게 보일 수 있습니다. 코드가 어떻게 문자열일 수 있습니까? 하지만 자바스크립트에서는 이런 일이 흔합니다. 데이터와 코드의 구분이 모호합니다.

//可以这样创建函数
var fn = new Function("arg1", "arg2", "return arg1 * arg2;");
fn(2, 3); //6 

이렇게 하면 코드를 다른 함수에 전달할 수도 있고, 일반 변수나 객체를 전달할 수도 있다는 장점이 있습니다(코드는 말 그대로 객체이기 때문입니다).

 콜백 기능 전달

함수를 매개변수로 전달하는 것은 쉽습니다.

function fn(arg1, arg2, callback){
 var num = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
 callback(num);  //传递结果
}

fn(10, 20, function(num){
 console.log("Callback called! Num: " + num); 
});    //结果为10和20之间的随机数 

어쩌면 번거롭거나 다소 어리석게 보일 수도 있습니다. 결과를 정상적으로 반환해 보는 것은 어떨까요? 하지만 콜백 함수를 사용해야 한다면 그렇게 생각하지 않을 수도 있습니다!

방해하지 마세요

기존 함수는 매개변수 형식으로 데이터를 입력하고 반환문을 사용하여 값을 반환합니다. 이론적으로 함수의 끝에 return 문이 있는데 구조적으로는 입력 지점과 출력 지점입니다. 이는 이해하기 더 쉽습니다. 함수는 기본적으로 입력과 출력 간의 구현 프로세스를 매핑한 것입니다.

그런데 함수 구현 과정이 너무 길면 함수 처리가 완료될 때까지 기다리나요, 아니면 비동기 처리를 위해 콜백 함수를 사용하나요? 이 경우 AJAX 요청과 같은 콜백 함수를 사용하는 것이 중요합니다. 처리를 위해 콜백 함수를 사용하면 코드는 헛되이 기다리지 않고 다른 작업을 계속 수행할 수 있습니다. 실제 개발에서는 JavaScript에서 비동기 호출이 자주 사용되며 여기서는 적극 권장됩니다!

다음은 AJAX를 사용하여 XML 파일을 로드하고 call() 함수를 사용하여 요청된 개체의 컨텍스트에서 콜백 함수를 호출하는 보다 포괄적인 예입니다.

function fn(url, callback){
 var httpRequest;    //创建XHR
 httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :   //针对IE进行功能性检测
    window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;
 
 httpRequest.onreadystatechange = function(){
  if(httpRequest.readystate === 4 && httpRequest.status === 200){  //状态判断
   callback.call(httpRequest.responseXML); 
  }
 };
 httpRequest.open("GET", url);
 httpRequest.send();
}

fn("text.xml", function(){    //调用函数
 console.log(this);   //此语句后输出
});

console.log("this will run before the above callback.");  //此语句先输出 

요청은 비동기식으로 처리됩니다. 즉, 요청을 시작할 때 요청이 완료되면 함수를 호출하라고 지시합니다. 실제 상황에서 onreadystatechange 이벤트 핸들러는 요청 실패 상황도 고려해야 합니다. 여기서는 xml 파일이 존재하고 브라우저에서 성공적으로 로드될 수 있다고 가정합니다. 이 예에서는 비동기 함수가 onreadystatechange 이벤트에 할당되므로 즉시 실행되지 않습니다.

결국 두 번째 console.log 문이 먼저 실행되는 이유는 요청이 완료될 때까지 콜백 함수가 실행되지 않기 때문입니다.

위의 예시는 이해하기 쉽지 않으니, 다음 예시를 살펴보세요.

 
function foo(){
 var a = 10;
 return function(){
  a *= 2;
  return a;  
 }; 
}
var f = foo();
f(); //return 20.
f(); //return 40. 

  函数在外部调用,依然可以访问变量a。这都是因为javascript中的作用域是词法性的。函数式运行在定义它们的作用域中(上述例子中的foo内部的作用域),而不是运行此函数的作用域中。只要f被定义在foo中,它就可以访问foo中定义的所有的变量,即便是foo的执行已经结束。因为它的作用域会被保存下来,但也只有返回的那个函数才可以访问这个保存下来的作用域。返回一个内嵌匿名函数是创建闭包最常用的手段。

回调是什么?

看维基的 Callback_(computer_programming) 条目:

In computer programming, a callback is a reference to a piece of executable code that is passed as an argument to other code.

jQuery文档How jQuery Works#Callback_and_Functio...条目:

A callback is a function that is passed as an argument to another function and is executed after its parent function has completed. The special thing about a callback is that functions that appear after the "parent" can execute before the callback executes. Another important thing to know is how to properly pass the callback. This is where I have often forgotten the proper syntax.

百科:回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

因此,回调本质上是一种设计模式,并且jQuery(包括其他框架)的设计原则遵循了这个模式。

在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。

因此callback 不一定用于异步,一般同步(阻塞)的场景下也经常用到回调,比如要求执行某些操作后执行回调函数。

例子
一个同步(阻塞)中使用回调的例子,目的是在func1代码执行完成后执行func2。

var func1=function(callback){
  //do something.
  (callback && typeof(callback) === "function") && callback();
}

func1(func2);
  var func2=function(){
}


异步回调的例子:

$(document).ready(callback);

$.ajax({
 url: "test.html",
 context: document.body
}).done(function() { 
 $(this).addClass("done");
}).fail(function() { alert("error");
}).always(function() { alert("complete"); 
});
/**
注意的是,ajax请求确实是异步的,不过这请求是由浏览器新开一个线程请求,当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理。*/

回调什么时候执行

回调函数,一般在同步情境下是最后执行的,而在异步情境下有可能不执行,因为事件没有被触发或者条件不满足。

回调函数的使用场合

资源加载:动态加载js文件后执行回调,加载iframe后执行回调,ajax操作回调,图片加载完成执行回调,AJAX等等。
DOM事件及Node.js事件基于回调机制(Node.js回调可能会出现多层回调嵌套的问题)。

setTimeout的延迟时间为0,这个hack经常被用到,settimeout调用的函数其实就是一个callback的体现

链式调用:链式调用的时候,在赋值器(setter)方法中(或者本身没有返回值的方法中)很容易实现链式调用,而取值器(getter)相对来说不好实现链式调用,因为你需要取值器返回你需要的数据而不是this指针,如果要实现链式方法,可以用回调函数来实现setTimeout、setInterval的函数调用得到其返回值。由于两个函数都是异步的,即:他们的调用时序和程序的主流程是相对独立的,所以没有办法在主体里面等待它们的返回值,它们被打开的时候程序也不会停下来等待,否则也就失去了setTimeout及setInterval的意义了,所以用return已经没有意义,只能使用callback。callback的意义在于将timer执行的结果通知给代理函数进行及时处理。

回调函数的传递

上面说了,要将函数引用或者函数表达式作为参数传递。

$.get('myhtmlpage.html', myCallBack);//这是对的
$.get('myhtmlpage.html', myCallBack('foo', 'bar'));//这是错的,那么要带参数呢?
$.get('myhtmlpage.html', function(){//带参数的使用函数表达式
myCallBack('foo', 'bar');
});


另外,最好保证回调存在且必须是函数引用或者函数表达式:
(callback && typeof(callback) === "function") && callback();

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.