一、介绍:

1、前提:在 js 中,函数也是对象,可以赋值给变量,可以作为参数放在函数的参数列表中,如:

var doSomething = function(a,b){return a + b;
}console.log(doSomething(2,3));

2、概念:callback 是一种特殊的函数,这个函数被作为参数传给另一个函数去调用,这样的函数就是回调函数。回调,顾名思义,回头再调。回调与同步、异步并没有直接的联系,回调只是一种实现方式,既可以有同步回调,也可以有异步回调,还可以有事件处理回调和延迟函数回调。

3、语法:在大多数编程语言中,函数的形参总是从外向内传递参数,但在JS中,如果形参碰到“关键字” callback 则完全相反,它表示从内向外反向调用某个外部函数。

二、举例

1、举例介绍:

(1)第一步:

var fs = require("fs");
var cfunction f(param) {console.log(param)
}function writeFile() {fs.writeFile('input.txt', 'fs.writeFile 写入文件的内容', function (err) {if (!err) {console.log("文件写入完成")c = 1}});
}c = 0
writeFile()
f(c)

打印结果为0,因为程序运行到writeFile()这一行的时候,是一个比较耗时的IO操作,JS碰到这种操作并不会停在原地一直等待直到函数执行完毕,而是直接运行下一条代码(即f(c)),而此时 c = 1这一行代码其实并没有被执行到,所以打印出来的结果还是0 !,如果希望打印1,可以使用第二步的代码:

(2)第二步:

var fs = require("fs");
var cfunction f(param) {console.log(param)
}function writeFile() { fs.writeFile('input.txt', 'fs.writeFile 写入文件的内容', function (err) {if (!err) {console.log("文件写入完成")c = 1f(c)}});
}c = 0
writeFile() 

这样结果是对的,但是改成这样并不完美,因为这么做就相当于将f()写死在writeFile()里了,如果此处我想根据不同的场景调用不同的函数还要写几个不同的writeFile(),而他们之间的区别仅仅是最后调用的那个函数不同,这里就体现callback的作用了(准确地说callback并不真的是Javascript里的关键字,只是大家都约定成俗把callback这个单词作为回调函数的默认选择)。看下使用回调函数后的代码:

(3)第三步:回调函数写法

var fs = require("fs");function f(param) {console.log(param)
}function writeFile(callback) { //callback,表示这个参数不是一个普通变量,而是一个函数fs.writeFile('input.txt', 'fs.writeFile 写入文件的内容', function (err) {if (!err) {console.log("文件写入完成")c = 1callback(c) // 因为我们传进来的函数名是f(),所以此行相当于调用一次f(c)}});
}
var c = 0
writeFile(f) // 函数f作为一个参数传进writeFile函数

经过改造后的代码出现了两次callback,第一个callback出现在writeFile的形参里,起定义的作用,表示这个参数并不是一个普通变量,而是一个函数,即所谓的“以函数为参数”。 第二个callback出现在c = 1下面,表示此处“执行”从形参传递进来的那个函数。这样一来,writeFile()函数在执行完毕之后到底调用哪个函数就变“活”了,如果我们想writeFile()函数执行完之后并不是像第二个例子那样只能调用f(),而是还有别的函数比如说x() y() z(),那么只需要写成 writeFile(x),writeFile(y)... 就行了。PS: 此处并不一定非要写为“callback”,你可以任意写成a,b,c...callback只是一种约定俗成的写法,它明确地告诉代码阅读者:此处是一个回调函数。

但是这步写法不够简洁,一些函数的形参列表里直接嵌套一个函数的情况,其本质上仍然是回调函数,因为没有了函数名,所以也称匿名函数。看下最终的简化写法:

(4)第四步:匿名回调函数

var fs = require("fs");function writeFile(callback) { fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {if (!err) {console.log("文件写入完毕!")c = 1callback(c) }});
}
var c = 0
writeFile(function (param) {console.log(param)
})

这是最简洁的写法,再举几个例子:

var doit = function(callback)
{var a = 1,b = 2,c = 3;var t = callback(a,b,c);return t + 10;
};
var d = doit(function(x,y,z){return (x+y+z);
});
console.log(d);
export default {created() {this.testCallBack();},methods: {testCallBack() {let param = '测试'this.myCallback(param, function (arg1, arg2) {alert('这是回调' + arg1 + ' ' + arg2)});},myCallback(param, callback) {setTimeout(() => {alert(param)callback(param, '222');}, 1000);}}
}
readImageFile(origin, quality, file) {let that = this;let fileName = file.name;let reader = new FileReader();reader.onload = function(evt) {let base64File = evt.target.result;that.imageCompress(base64File,origin,{quality},function(result) {let blobFile = that.dataURLtoBlob(result);let compressFile = new window.File([blobFile], fileName, { type: file.type });that.uploadFile(compressFile);});};reader.readAsDataURL(file);},// 压缩图片imageCompress(path, Orientation, obj, callback) {let img = new Image();img.src = path;img.onload = function() {let that = this;// 默认按比例压缩let imgWidth = that.width;let imgHeight = that.height;let scale = imgWidth / imgHeight;if (imgWidth > MAX_IMAGE_WIDTH) {imgWidth = MAX_IMAGE_WIDTH;imgHeight = imgWidth / scale;}let quality = obj.quality || 0.7; // 默认图片质量为0.7// 生成canvaslet canvas = document.createElement('canvas');let ctx = canvas.getContext('2d');let anw = document.createAttribute('width');let anh = document.createAttribute('height');anw.nodeValue = imgWidth;anh.nodeValue = imgHeight;canvas.setAttributeNode(anw);canvas.setAttributeNode(anh);ctx.drawImage(that, 0, 0, imgWidth, imgHeight);// quality值越小,所绘制出的图像越模糊let base64 = canvas.toDataURL('image/jpeg', quality);// 回调函数返回base64的值callback(base64);};},
function doSomething(msg, callback){alert(msg);if(typeof callback == "function") callback();}
doSomething("回调函数", function(){alert("匿名函数实现回调!");}); 

2、常见的回调函数例子:

三、回调函数中this的指向:callback中的this指向window。可以使用Call和Apply函数来改变this指向,每个Javascript中的函数都有两个方法:Call 和 Apply。这些方法被用来设置函数内部的this对象以及给此函数传递变量。

举例:

var clientData = {id: 096545,fullName: "Not Set",//setUsrName是一个在clientData对象中的方法setUserName: function (firstName, lastName){this.fullName = firstName + " " + lastName;}
} function getUserInput(firstName, lastName, callback){//code .....//调用回调函数存储callback(firstName, lastName);
}getUserInput("Barack","Obama",clientData.setUserName);console.log(clientData.fullName);  //Not Setconsole.log(window.fullName);  //Barack Obama

在上面的代码中,当clientData.setUsername被执行时,this.fullName并没有设置clientData对象中的fullName属性,它将设置window对象中的fullName属性。

下面我们看下Apply函数实现,Call函数类似。(call接收的第一个参数为被用来在函数内部当做this的对象,传递给函数的参数被挨个传递。Apply函数的第一个参数也是在函数内部作为this的对象,然而最后一个参数确是传递给函数的值的数组。)

//注意到我们增加了新的参数作为回调对象,叫做“callbackObj”
function getUserInput(firstName, lastName, callback ,callbackObj){//code .....callback.apply(callbackObj, [firstName, lastName]);
}getUserInput("Barack", "Obama", clientData.setUserName, clientData);console.log(clientData.fullName); //Barack Obama

四、回调函数的使用场景:

1、回调函数经常使用于以下场景:

  • 异步调用(例如读取文件,进行HTTP请求,动态加载js文件,加载iframe资源后,图片加载完成执行回调等等)
  • 事件监听器/处理器
  • setTimeout和setInterval方法
  • 一般情况:精简代码

2、以异步调用为例,回调函数与异步编程:回调函数是实现异步编程的利器,在程序运行中,当某些请求过程漫长,我们有时没必要选择等待请求完成继续处理下一个任务,这时使用回调函数进行异步处理可以大大提高程序执行效率。例如:AJAX请求。若是使用回调函数进行处理,代码就可以继续进行其他任务,而无需空等。实际开发中,经常在javascript中使用异步调用!下面有个使用AJAX加载XML文件的示例,并且使用了call()函数,在请求对象(requested object)上下文中调用回调函数。

function fn(url, callback){var httpRequest;    //创建XHRhttpRequest = 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.");  //此语句先输出

五、“回调地狱”问题以及解决方案:许多层级的回调函数堆积以致代码层次过多称为回调地狱。

vue 函数(二):callback回调函数相关推荐

  1. 【日常记录】函数指针与回调函数

    一.函数指针及其定义和用法  1.什么是函数指针? 2.如何用函数指针调用函数 二.回调函数(callback) 1. 什么是回调函数? 2. 为什么要使用回调函数? 3.怎么使用回调函数? 4. 怎 ...

  2. callback 回调函数

    一.调用和回调的定义 回调函数有点绕,可用简单的一个案例说明: A给B打电话,问:1+1等于几? B说,我也忘了,我得想一会,想好了再告诉你.这时比较好的方式是断开电话链接,等B想好了再告诉A.于是他 ...

  3. 十一、【TF2】Callback 回调函数

    TF2 Callback 一.回调函数简介 二.TF2中的内置回调函数 1- tf.keras.callbacks.BaseLogger 基础日志 2- tf.keras.callbacks.Hist ...

  4. javascript~callback回调函数

    函数是对象,所以它可以作为一个参数传递给其他函数. 回调函数作为一个参数传递给其他函数时是没有括号的,只有函数名:使用括号表示立即执行回调函数callback.我们只希望传递一个函数的引用,让其他函数 ...

  5. js接收php 回调,JS callback回调函数的使用(附代码)

    这次给大家带来JS callback回调函数的使用(附代码),JS callback回调函数使用的注意事项有哪些,下面就是实战案例,一起来看一下. 在使用开源项目的时候经常会使用到回调函数,如果把回调 ...

  6. [C] 二、回调函数

    二.回调函数 作者:解琛 时间:2020 年 9 月 11 日 回调函数 函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数. populate_array 函数定义了 ...

  7. callback(回调函数)

    先讲点题外话. 编程分为两类:系统编程(system programming)和应用编程(application programming).所谓系统编程,简单来说,就是编写库:而应用编程就是利用写好的 ...

  8. Callback回调函数介绍(C语言)

    目录 1. 回调函数的定义 2. 为什么要用回调函数 3. 怎么用回调函数 3.1 怎么使用没有参数的回调函数 3.2 怎么使用带参数的回调函数 1. 回调函数的定义 最近在工作中经常用到回调函数ca ...

  9. 【C语言进阶深度学习记录】三十二 函数指针与使用函数指针实现回调函数

    回调函数是非常重要的概念 文章目录 1 函数的类型 2 函数指针 2.1 函数指针的使用 2.2 使用函数指针实现回调函数 3 总结 1 函数的类型 跟以前学数组的时候是一样的,C语言中的数组是有自己 ...

  10. 【Android 高性能音频】AAudio 音频流 PCM 采样 的 采样 缓冲 播放 的 连续机制 ( 数据回调机制 | 数据回调函数指针 | 实现数据回调函数 | 设置数据回调函数 )

    文章目录 I . AAudio 音频流 采样 缓冲 播放 的连续机制 II . AAudio 音频流 数据回调函数 函数指针类型定义 III . AAudio 音频流 数据回调函数 实现 IV . A ...

最新文章

  1. Nature封面论文创意被剽窃?UC圣迭戈付向东实名举报中科院研究员抄袭
  2. 构造 ---- 最小没出现过的数(逆向构造) D. Replace by MEX
  3. Sumline常用快捷操作
  4. 卸载注册表_系统小技巧:软件卸载不了?这里办法多
  5. [BZOJ] 1637: [Usaco2007 Mar]Balanced Lineup
  6. primefaces_PrimeFaces:在动态生成的对话框中打开外部页面
  7. oracle 119(11.2.0.4),ORACLE 从 11.2.0.1 升级到 11.2.0.4 版本之ORA-00119问题处理纪实
  8. ps里面怎么插入流程图_流程图很难画?学会这3个方法,5分钟能绘制出好看又高级的流程图...
  9. linux搭建博客day2
  10. 如何阅读python源码_如何阅读源代码(转)
  11. 32位电脑ODBC连接
  12. oracle获取当前年上一年时间,Oracle获取一年中的所有日期和一个月中的所有日期...
  13. 图像匹配论文与方法超全整理
  14. 《移动端UI框架》Vant
  15. 【十大思想实验之中的一个】电车难题
  16. 【前端面经】H5-语义化标签的理解
  17. 随身WIFI折腾日记(一)---霓虹灯
  18. 关于解决 Failed to prepare partial IU:
  19. WPF教程(一)---创建一个WPF程序基础知识
  20. 【系统分析师之路】系统分析师通过人数与通过率探秘

热门文章

  1. 强烈推荐APP破解常用工具集合!最强总结
  2. python爬取酷狗音乐json数据为空_python使用beautifulsoup4爬取酷狗音乐
  3. C语言负数的小数次方,c语言 10 负次方
  4. Win10怎么把登录密码去掉
  5. 如何重装win10应用商店?
  6. 解决fences2.01在win8.1的状态下无法移动桌面图标问题
  7. linux服务器运维基础学习
  8. 运维工程师必须掌握的基础技能有哪些?
  9. PS制作一寸带白框的证件照
  10. 华为U2000网管研究实录 (4) - 运行分析(系统监控客户端)