1. 首页
  2. IT资讯

「JavaScript基础」回调(callback)是什么

“u003Cdivu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp9.pstatp.comu002Flargeu002Fdfic-imagehandleru002Fa5d7a26a-d986-42be-a3b7-4bef0a854619″ img_width=”1024″ img_height=”683″ alt=”「JavaScript基础」回调(callback)是什么” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E上篇文章u003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6711077688217436676u002F?group_id=6711077688217436676″ target=”_blank”u003EJavaScript基础——你真的清楚JavaScript是什么吗?u003Cu002Fau003E,我们明白了JavaScript是一个单线程、非阻塞、异步、解释性语言,清楚了什么是单线程、进程、阻塞、调用堆栈、异步回调、任务循环等感念,没看的或者不清楚的建议点击《u003Ca class=”pgc-link” data-content=”mp” href=”https:u002Fu002Fwww.toutiao.comu002Fi6711077688217436676u002F?group_id=6711077688217436676″ target=”_blank”u003EJavaScript基础——你真的清楚JavaScript是什么吗?u003Cu002Fau003E再看一遍,只有理解了,才能轻松阅读理解本篇文章内容。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E什么是callback?u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003EJavaScript 是单线程工作,这意味着两段脚本不能同时运行,而是必须一个接一个地运行。我们人类是多线程工作。您可以使用多个手指打字,可以一边开车一边与人交谈。唯一一个会妨碍我们的是打喷嚏,因为当我们打喷嚏的时候,所有当前进行的活动都必须暂停。这真是非常讨厌,尤其是当您在开车并想与人交谈时。您可不想编写像打喷嚏似的代码。JavaScript由于单线程限制,防止阻塞,只能通过异步函数的调用方式,把需要延迟处理的事件放入事件循环队列。到目前为止,回调是编写和处理JavaScript程序异步逻辑的最常用方式。说了这么多,既然回调这么重要,到底什么是回调(callback)呢?u003Cu002Fpu003Eu003Cpu003E简单的定义:回调就是一个在另外一个函数执行完后要执行的函数u003Cu002Fpu003Eu003Cpu003E复杂的定义:在JavaScript中,函数是对象。因此函数可以将函数作为参数,并且可以由其他函数进行返回。执行此操作的函数称为高阶函数。任何作为参数传递的函数都称为回调函数。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E为什么需要回调?u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp3.pstatp.comu002Flargeu002Fdfic-imagehandleru002F487774e8-4f3d-48a3-94be-7bcb885a1863″ img_width=”1023″ img_height=”795″ alt=”「JavaScript基础」回调(callback)是什么” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E开篇已经介绍了JavaScript是单线程的,需要通回调函数处理异步相关的逻辑,理论还是过于生硬,我们还是来看段代码吧:u003Cu002Fpu003Eu003Cpreu003Efunction first(){u003Cbru003Econsole.log(1);u003Cbru003E}u003Cbru003Efunction second(){u003Cbru003Econsole.log(2);u003Cbru003E}u003Cbru003Efirst();u003Cbru003Esecond();u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E正如你所料,先执行first函数,再执行second函数,控制台将输出以下内容:u003Cu002Fpu003Eu003Cpreu003E1u003Cbru003E2u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E目前看来没什么问题,如果first()函数中含有某种无法立即执行的函数呢?例如,我们必须发送请求然后等待结果响应的API请求?为了模拟API请求,我们可以使用setTimeout函数模拟。我们将函数延迟500毫秒来模拟请求,我们更改后代码如下:u003Cu002Fpu003Eu003Cpreu003Efunction first(){u003Cbru003Eu002Fu002F Simulate a code delayu003Cbru003EsetTimeout( function(){u003Cbru003Econsole.log(1);u003Cbru003E}, 500 );u003Cbru003E}u003Cbru003Efunction second(){u003Cbru003Econsole.log(2);u003Cbru003E}u003Cbru003Efirst();u003Cbru003Esecond();u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E我们将 console.log(1) 延迟500毫秒输出,这段代码会怎么输出呢?u003Cu002Fpu003Eu003Cpreu003E2u003Cbru003E1u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E我们希望的顺序先执行first,再执行second,但是由于JavaScript是异步的,所有的延迟处理都要放入循环队列里,因此事与愿违,不能按照我们的希望顺序输出。如果希望这段代码按照我们的意愿输出,我们可以使用回调函数,确保某些代码执行完了,在循序执行另外一段代码。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E创建回调u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E说了这么多,让我们创建一个简单的回调!u003Cu002Fpu003Eu003Cpu003E我们打开编辑器,先输入如下代码:u003Cu002Fpu003Eu003Cpreu003Efunction doHomework(subject) {u003Cbru003Ealert(`Starting my ${subject} homework.`);u003Cbru003E}u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E上面我们创建了doHomeWork的函数,我们接受一个变量,通过控制台调用,将得到下面的提示:u003Cu002Fpu003Eu003Cpreu003EdoHomework(‘math’);u003Cbru003Eu002Fu002F Alerts: Starting my math homework.u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E接着,我们开始添加回调,在doHomework函数中添加一个参数callback,然后在第二个参数中回调我们定义的函数。代码如下:u003Cu002Fpu003Eu003Cpreu003Efunction doHomework(subject, callback) {u003Cbru003Ealert(`Starting my ${subject} homework.`);u003Cbru003Ecallback();u003Cbru003E}u003Cbru003EdoHomework(‘math’, function() {u003Cbru003Ealert(‘Finished my homework’);u003Cbru003E});u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E正如你希望的,我们在控制台里运行上述代码,将会受到两个连续的alert,Starting my math homework,然后弹出 Finished my homework。u003Cu002Fpu003Eu003Cpu003E但是回调函数并不是非得在调用函数中定义,我们可以单独定义,修改后的代码如下:u003Cu002Fpu003Eu003Cpreu003Efunction doHomework(subject, callback) {u003Cbru003Ealert(`Starting my ${subject} homework.`);u003Cbru003Ecallback();u003Cbru003E}u003Cbru003Efunction alertFinished(){u003Cbru003Ealert(‘Finished my homework’);u003Cbru003E}u003Cbru003EdoHomework(‘math’, alertFinished);u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E此示例的输出结果和上段代码的结果一致,我们实现了在doHomework函数中调用alertFinished,实现了函数作为参数进行传递,实现了回调函数的创建。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E用回调写一段真实业务场景的代码!u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E例如我们有一个需求,用NodeJs实现从论坛帖子列表中显示其中的一个帖子的信息及留言列表信息,代码如下:u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003EDBu002Fposts.json(帖子列表数据)u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003E[u003Cbru003E{u003Cbru003E”id”: “001”,u003Cbru003E”title”: “Greeting”,u003Cbru003E”text”: “Hello World”,u003Cbru003E”author”: “Jane Doe”u003Cbru003E},u003Cbru003E{u003Cbru003E”id”: “002”,u003Cbru003E”title”: “JavaScript 101″,u003Cbru003E”text”: “The fundamentals of programming.”,u003Cbru003E”author”: “Alberta Williams”u003Cbru003E},u003Cbru003E{u003Cbru003E”id”: “003”,u003Cbru003E”title”: “Async Programming”,u003Cbru003E”text”: “Callbacks, Promises and Asyncu002FAwait.”,u003Cbru003E”author”: “Alberta Williams”u003Cbru003E}u003Cbru003E]u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003EDBu002Fcomments.json(评论列表)u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003E[u003Cbru003E{u003Cbru003E”id”: “phx732″,u003Cbru003E”postId”: “003”,u003Cbru003E”text”: “I don’t get this callback stuff.”u003Cbru003E},u003Cbru003E{u003Cbru003E”id”: “avj9438″,u003Cbru003E”postId”: “003”,u003Cbru003E”text”: “This is really useful info.”u003Cbru003E},u003Cbru003E{u003Cbru003E”id”: “gnk368″,u003Cbru003E”postId”: “001”,u003Cbru003E”text”: “This is a test comment.”u003Cbru003E}u003Cbru003E]u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003Eu003Cstrongu003EIndex.jsu003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpreu003Econst fs = require(‘fs’);u003Cbru003Econst path = require(‘path’);u003Cbru003Econst postsUrl = path.join(__dirname, ‘dbu002Fposts.json’);u003Cbru003Econst commentsUrl = path.join(__dirname, ‘dbu002Fcomments.json’);u003Cbru003Eu002Fu002Freturn the data from our fileu003Cbru003Efunction loadCollection(url, callback) {u003Cbru003Efs.readFile(url, ‘utf8’, function(error, data) {u003Cbru003Eif (error) {u003Cbru003Econsole.log(error);u003Cbru003E} else {u003Cbru003Ereturn callback(JSON.parse(data));u003Cbru003E}u003Cbru003E});u003Cbru003E}u003Cbru003Eu002Fu002Freturn an object by idu003Cbru003Efunction getRecord(collection, id, callback) {u003Cbru003Evar collectobj=collection.find(function(element){u003Cbru003Ereturn element.id == id;u003Cbru003E});u003Cbru003Ecallback(collectobj);u003Cbru003Ereturn collectobj;u003Cbru003E}u003Cbru003Eu002Fu002Freturn an array of comments for a postu003Cbru003Efunction getCommentsByPost(comments, postId) {u003Cbru003Ereturn comments.filter(function(comment){u003Cbru003Ereturn comment.postId == postId;u003Cbru003E});u003Cbru003E}u003Cbru003EloadCollection(postsUrl, function(posts){u003Cbru003EloadCollection(commentsUrl, function(comments){u003Cbru003EgetRecord(posts, “001”, function(post){u003Cbru003Econst postComments = getCommentsByPost(comments, post.id);u003Cbru003Econsole.log(post);u003Cbru003Econsole.log(postComments);u003Cbru003E});u003Cbru003E});u003Cbru003E});u003Cbru003Eu003Cu002Fpreu003Eu003Cpu003E大家请注意,我们在loadCollection函数中我们没有使用tryu002Fcatch,使用的是ifu002Felse,因为catch无法从readFile方法中获取错误。上述代码还需要完善,我没有包含任何错误处理。如果在任何步骤中发生错误,程序将无法继续。u003Cu002Fpu003Eu003Cpu003E错误处理是很重要的事情,我们写代码时要严格对待,比如我们要编写一个用户登录的功能。涉及从网页表单里获取用户名和密码,查询我们的数据库,确认用户信息是否正确,验证通过后,将用户引导到用户中心页面。如果用户名密码格式不正确,用户名密码不正确,我们应该将错误信息返回给用户,并引导用户重新登录。u003Cu002Fpu003Eu003Cpu003Eu003Cstrongu003E总结u003Cu002Fstrongu003Eu003Cu002Fpu003Eu003Cpu003E很好!我们一起把回调的内容学完了,理解了什么是回调,异步编程是我们的代码中使用的一种方法,用于推迟事件以便以后执行。当您处理异步任务时,回调是一种解决方案,以便它们按顺序执行。u003Cu002Fpu003Eu003Cdiv class=”pgc-img”u003Eu003Cimg src=”http:u002Fu002Fp1.pstatp.comu002Flargeu002Fdfic-imagehandleru002F4cb3317f-417f-46f6-8969-724e8424abb5″ img_width=”1200″ img_height=”674″ alt=”「JavaScript基础」回调(callback)是什么” inline=”0″u003Eu003Cp class=”pgc-img-caption”u003Eu003Cu002Fpu003Eu003Cu002Fdivu003Eu003Cpu003E如果我们有多个任务依赖于前几个任务的结果,那我们就要使用多个嵌套回调,但是就会引发“回调地域”(过多的回调嵌套会使得代码变得难以理解与维护),还好Promise解决了“回调地狱”的问题,让我们以同步的方式编写代码,小编将会再下篇文章里进行详细介绍,敬请期待!u003Cu002Fpu003Eu003Cpu003E更多精彩内容,请微信u003Cstrongu003E关注”前端达人”公众号u003Cu002Fstrongu003E!u003Cu002Fpu003Eu003Cu002Fdivu003E”

原文始发于:「JavaScript基础」回调(callback)是什么

主题测试文章,只做测试使用。发布者:杀手梦三刀,转转请注明出处:http://www.cxybcw.com/10786.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code