转自: http://recurial.com/programming/understanding-callback-functions-in-javascript/
Callback functions are extremely important in Javascript. They’re pretty much everywhere. Originally coming from a more traditional C/Java background I had trouble with this (and the whole idea of asynchronous programming), but I’m starting to get the hang of it. Strangely, I haven’t found any good introductions to callback functions online — I mainly found bits of documentation on the call() and apply() functions, or brief code snippits demonstrating their use — so, after learning the hard way I decided to try to write a simple introduction to callbacks myself.
Functions are objects
To understand callback functions you first have to understand regular functions. This might seen like a “duh” thing to say, but functions in Javascript are a bit odd.
Functions in Javascript are actually objects. Specifically, they’reFunction
objects created with the Function
constructor. AFunction
object contains a string which contains the Javascript code of the function. If you’re coming from a language like C or Java that might seem strange (how can code be a string?!) but it’s actually run-of-the-mill for Javascript. The distinction between code and data is sometimes blurred.
1 |
// you can create a function by passing the |
2 |
// Function constructor a string of code |
3 |
var func_multiply = new Function( "arg1" , "arg2" , "return arg1 * arg2;" ); |
4 |
func_multiply(5,10); // => 50 |
One benefit of this function-as-object concept is that you can pass code to another function in the same way you would pass a regular variable or object (because the code is literally just an object).
Passing a function as a callback
Passing a function as an argument is easy.
01 |
// define our function with the callback argument |
02 |
function some_function(arg1, arg2, callback) { |
03 |
// this generates a random number between |
05 |
var my_number = Math.ceil(Math.random() * |
06 |
(arg1 - arg2) + arg2); |
07 |
// then we're done, so we'll call the callback and |
12 |
some_function(5, 15, function (num) { |
13 |
// this anonymous function will run when the |
15 |
console.log( "callback called! " + num); |
It might seem silly to go through all that trouble when the value could just be returned normally, but there are situations where that’s impractical and callbacks are necessary.
Don’t block the way
Traditionally functions work by taking input in the form of arguments and returning a value using a return statement (ideally a single return statement at the end of the function: one entry point and one exit point). This makes sense. Functions are essentially mappings between input and output.
Javascript gives us an option to do things a bit differently. Rather than wait around for a function to finish by returning a value, we can use callbacks to do it asynchronously. This is useful for things that take a while to finish, like making an AJAX request, because we aren’t holding up the browser. We can keep on doing other things while waiting for the callback to be called. In fact, very often we are required (or, rather, strongly encouraged) to do things asynchronously in Javascript.
Here’s a more comprehensive example that uses AJAX to load an XML file, and uses the call() function to call a callback function in the context of the requested object (meaning that when we call the this
keyword inside the callback function it will refer to the requested object):
01 |
function some_function2(url, callback) { |
02 |
var httpRequest; // create our XMLHttpRequest object |
03 |
if (window.XMLHttpRequest) { |
04 |
httpRequest = new XMLHttpRequest(); |
05 |
} else if (window.ActiveXObject) { |
06 |
// Internet Explorer is stupid |
08 |
ActiveXObject( "Microsoft.XMLHTTP" ); |
11 |
httpRequest.onreadystatechange = function () { |
12 |
// inline function to check the status |
14 |
// this is called on every state change |
15 |
if (httpRequest.readyState === 4 && |
16 |
httpRequest.status === 200) { |
17 |
callback.call(httpRequest.responseXML); |
18 |
// call the callback function |
21 |
httpRequest.open( 'GET' , url); |
25 |
some_function2( "text.xml" , function () { |
28 |
console.log( "this will run before the above callback" ); |
In this example we create the httpRequest
object and load an XML file. The typical paradigm of returning a value at the bottom of the function no longer works here. Our request is handled asynchronously, meaning that we start the request and tell it to call our function when it finishes.
We’re using two anonymous functions here. It’s important to remember that we could just as easily be using named functions, but for sake of brevity they’re just written inline. The first anonymous function is run every time there’s a state change in our httpRequest
object. We ignore it until the state is 4 (meaning it’s done) and the status is 200 (meaning it was successful). In the real world you’d want to check if the request failed, but we’re assuming the file exists and can be loaded by the browser. This anonymous function is assigned to httpRequest.onreadystatechange
, so it is not run right away but rather called every time there’s a state change in our request.
When we finally finish our AJAX request, we not only run the callback function but we use the call()
function. This is a different way of calling a callback function. The method we used before of just running the function would work fine here, but I thought it would be worth demonstrating the use of the call()
function. Alternatively you could use the apply()
function (the difference between the two is beyond the scope of this tutorial, but it involves how you pass arguments to the function).
The neat thing about using call()
is that we set the context in which the function is executed. This means that when we use thethis
keyword inside our callback function it refers to whatever we passed as the first argument for call()
. In this case, when we refer to this inside our anonymous callback function we are referring to theresponseXML
from the AJAX request.
Finally, the second console.log statement will run before the first, because the callback isn’t executed until the request is over, and until that happens the rest of the code goes right on ahead and keeps running.
Wrapping it up
Hopefully now you should understand callbacks well enough to use them in your own code. I still find it hard to structure code that is based around callbacks (it ends up looking like spaghetti… my mind is too accustomed to regular structured programming), but they’re a very powerful tool and one of the most interesting parts of the Javascript language.
- 【JavaScript】Understanding callback functions in Javascript
Callback functions are extremely important in Javascript. They’re pretty much everywhere. Originally ...
- Understand JavaScript Callback Functions and Use Them
In JavaScript, functions are first-class objects; that is, functions are of the type Object and they ...
- 理解callback function in javascript
以下内容主要摘自[1,2] (1)In javascript, functions are first-class objects, which means functions can be used ...
- Understanding RequireJS for Effective JavaScript Module Loading
Modular programming is used to break large applications into smaller blocks of manageable code. Modu ...
- [TypeScript] Simplify asynchronous callback functions using async/await
Learn how to write a promise based delay function and then use it in async await to see how much it ...
- A chatroom for all! Part 1 - Introduction to Node.js(转发)
项目组用到了 Node.js,发现下面这篇文章不错.转发一下.原文地址:<原文>. ------------------------------------------- A chatro ...
- Understanding JavaScript Function Invocation and "this"
Understanding JavaScript Function Invocation and "this" 11 Aug 2011 Over the years, I've s ...
- JavaScript Callback 回调函数
JavaScript callback回调函数 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这 ...
- 【JavaScript】Registering JavaScript object methods as callbacks
The registration of callback functions is very common in JavaScript web programming, for example to ...
随机推荐
- 卸载Linux内置的AMP软件
卸载Linux内置的AMP软件 在安装Linux软件的LAMP环境时,必须有一个前提:必须要完全卸载掉系统内置的AMP软件. 1.卸载httpd软件(Apache) 如果在卸载软件时出现依赖关系,我们 ...
- 支持向量机 support vector machine
SVM(support Vector machine) (1) SVM(Support Vector Machine)是从瓦普尼克(Vapnik)的统计学习理论发展而来的,主要针对小样本数据进行学习. ...
- Codevs 1080 线段树联系
题目描述 Description 一行N个方格,开始每个格子里都有一个整数.现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和:修改的规则是指定某一个格子x,加上或 ...
- 使用CInternetSession CHttpFile下载网页链接地址的文件
思路很清晰,使用CInternetSession创建CHttpFile对象.然后对该对象获取文件信息.进行文件读写操作均可. void DownloadFile(LPCTSTR szURL, LPCT ...
- silverlight Frame嵌套页面刷新问题
1.此方法将会刷新到主页面 private void btn_Click(object sender, RoutedEventArgs e) { HtmlPage.Window.Eval(" ...
- 生成动态前缀且自增号码的Oracle函数
create or replace Function GetInvitationNO(prev varchar2, num1 varchar2, num2 varchar2, sessionSetti ...
- ECSHOP的订单状态在数据库中的表现(order_status, shipping_status, pay_status)
echop的订单状态都是在ecs_order_info表中的字段里. 订单状态 未确认 取消 确认 已付款 配货中 已发货 已收货 退货 order_status 0 2 1 1 1 5 5 4 sh ...
- 在有跳板机的情况下,SecureCRT自动连接到目标服务器
为了服务器的安全,运维人员经常会要求我们先登录到跳板机,然后再SSH连接到目标服务器.但是这样是很繁琐的,每次在SecureCRT创建一个连接,都需要输入SSH命令,然后输入密码. 下面的方法可以实现 ...
- XAML 概述一
XAML的全称是Extensible Application Markup Language,就是我们所说的可扩展应用程序标记语言.XAML可以应用到许多不同领域,但主要用于构建用户界面. XAML是 ...
- 【nodejs】关于 alert 和 document
Microsoft Windows [版本 6.1.7601] 版权所有 (c) 2009 Microsoft Corporation.保留所有权利. C:\Windows\system32>n ...