[译] JavaScript:回调是什么鬼?

本文讲的是[译] JavaScript:回调是什么鬼?,




配合简单的示例,用短短 6 分钟学习和理解回调的基本知识。



回调  —— 题图来自 unsplash

回调是什么?

简单讲: 回调是指在另一个函数执行完成之后被调用的函数  ——  因此得名“回调”。

稍复杂地讲: 在 JavaScript 中,函数也是对象。因此,函数可以传入函数作为参数,也可以被其他函数返回。这样的函数称为高阶函数。被作为参数传入的函数就叫做回调函数。

^ 这听起来有点啰唆,让我们来看一些例子来简化一下。

为什么我们需要回调?

有一个非常重要的原因 —— JavaScript 是事件驱动的语言。这意味着,JavaScript 不会因为要等待一个响应而停止当前运行,而是在监听其他事件时继续执行。来看一个基本的例子:

function first(){
  console.log(1);
}

function second(){
  console.log(2);
}

first();
second();

正如你所料,first 函数首先被执行,随后 second 被执行 —— 控制台输出下面内容:

// 1
// 2

一切都如此美好。

但如果函数 first 包含某种不能立即执行的代码会如何呢?例如我们必须发送请求然后等待响应的 API 请求?为了模拟这种状况,我们将使用 setTimeout,它是一个在一段时间之后调用函数的 JavaScript 函数。我们将函数延迟 500 毫秒来模拟一个 API 请求,新代码长这样:

function first(){
// 模拟代码延迟
  setTimeout( function(){
console.log(1);
  }, 500 );
}

function second(){
  console.log(2);
}

first();
second();

现在理解 setTimeout() 是如何工作的并不重要,重要的是你看到了我们已经把console.log(1); 移动到了 500 秒延迟函数内部。那么现在调用函数会发生什么呢?

first();
second();

// 2
// 1

即使我们首先调用了 first() 函数,我们记录的输出结果却在 second() 函数之后。

这不是 JavaScript 没有按照我们想要的顺序执行函数的问题,而是 JavaScript 在继续向下执行 second() 之前没有等待 first() 响应的问题。

所以为什么给你看这个?因为你不能一个接一个地调用函数并希望它们按照正确的顺序执行。回调正是确保一段代码执行完毕之后再执行另一段代码的方式。

创建一个回调

好了,说了这么多,让我们创建一个回调!

首先,打开你的 Chrome 开发者工具(Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J),在控制台输入下面的函数声明:

function doHomework(subject) {
  alert(`Starting my ${subject} homework.`);
}

上面,我们已经创建了 doHomework 函数。我们的函数携带一个变量,是我们正在研究的课题。在控制台输入下面内容调用你的函数:

doHomework('math');

// Alerts: Starting my math homework.

现在把我们的回调加进来,我们传入 callback 作为 doHomework() 的最后一个参数。这个回调函数是我们定义在接下来要调用的 doHomework() 函数的第二个参数。

function doHomework(subject**, callback**) {
  alert(`Starting my ${subject} homework.`);
**callback();**
}

doHomework('math'**, function() {
  alert('Finished my homework');
}**);

如你所见,如果你将上面的代码输入控制台,你将依次得到两个警告:第一个是“starting homework”,接着是“finished homework”。

但是你的回调函数并不总是必须定义在函数调用里面,它们也可以定义在你代码中的其他位置,比如这样:

function doHomework(subject, callback) {
  alert(`Starting my ${subject} homework.`);
  callback();
}

function alertFinished(){
  alert('Finished my homework');
}

**doHomework('math', alertFinished);**

这个例子的结果和之前的例子完全一致。如你所见,我们在 doHomework() 函数调用中传入了alertFinished 函数定义作为参数!

实际应用案例

上周我发表了一篇关于如何用 38 行代码构建一个 Twitter 机器人的文章。文中的代码可以实现的唯一原因就是我使用了 Twitters API。当你向一个 API 发送请求,在你操作响应内容之前你必须等待这个响应。这是回调在实际应用中的绝佳案例。请求长这样:

T.get('search/tweets', params, function(err, data, response) {
  if(!err){
    // 这里是施展魔法之处
  } else {
    console.log(err);
  }
})
  • T.get 仅仅意味着我们将要向 Twitter 发送一个 get 请求
  • 这个请求中有三个参数:‘search/tweets’ 是请求的路径,params 是搜索参数,随后的一个匿名函数是我们的回调。

回调在这里很重要,因为在我们的代码继续运行之前我们需要等待一个来自服务端的响应。我们并不知道 API 请求会成功还是会失败,所以通过 get 向 search/tweets 发送了请求参数以后,我们要等待。一旦 Twitter 响应,我们的回调函数就被调用。Twitter 要么发送一个err(error)对象,要么发送一个 response 对象返回给我们。在我们的回调函数中我们可以使用 if() 语句来区分请求是否成功,然后相应地处理新数据。

你做到了

干得漂亮!你现在(理想状况下)已经理解了回调是什么,回调如何工作。这只是回调的冰山一角,记住学无止境啊!我每周都会更新一些文章/教程,如果你愿意接收每周一次的推送,点击这里输入你的邮箱订阅吧!





原文发布时间为:2017年6月22日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2024-09-29 11:48:09

[译] JavaScript:回调是什么鬼?的相关文章

[译]JavaScript 让 Monad 更简单(软件编写)(第十一部分)

本文讲的是[译]JavaScript 让 Monad 更简单(软件编写)(第十一部分), 原文地址:JavaScript Monads Made Simple 原文作者:Eric Elliott 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:yoyoyohamapi 校对者:IridescentMia WJoan Smoke Art Cubes to Smoke - MattysFlicks - (CC BY 2.0) (译注:该图是用 PS 将烟雾

[译] JavaScript 的函数式编程是一种反模式

本文讲的是[译] JavaScript 的函数式编程是一种反模式, 原文地址:Functional programming in JavaScript is an antipattern 原文作者:Alex Dixon 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:sunui 校对者:LeviDing.xekri 其实 Clojure 更简单些 写了几个月 Clojure 之后我再次开始写 JavaScript.就在我试着写一些很普通的东西的时候,我

[译] JavaScript 开发者年度调查报告

本文讲的是[译] JavaScript 开发者年度调查报告, 原文链接 : JavaScript Developer Survey Results 原文作者 : ponyfoo 译文出自 : 掘金翻译计划 译者 : sqrthree(根号三) 译者博客链接: [译]JavaScript 开发者年度调查报告 校对者: Zhangdroid 截至目前有超过了 5000 人参与了(该次调查),准确的说是 5350 人.我迫不及待的想要和大家分享一下这次调查的细节.在分享之前我想要感谢参与调查的每一个人

[译] Javascript 中多样的 this

本文讲的是[译] Javascript 中多样的 this, 原文地址:The many faces of this in javascript 原文作者:Michał Witkowski 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:lsvih 校对者:lampui, zerosrat 本文将尽量解释清楚 JavaScript 中最基础的部分之一:执行上下文(execution context).如果你经常使用 JS 框架,那理解 this 更是锦

[译]JavaScript规范-葵花宝典

原文:[译]JavaScript规范-葵花宝典 [译]JavaScript规范 译自:https://github.com/airbnb/javascript 类型 原始值: 相当于传值 string number boolean null undefined var foo = 1, bar = foo; bar = 9; console.log(foo, bar); // => 1, 9 复杂类型: 相当于传引用 object array function var foo = [1, 2],

关于Javascript回调函数的一个妙用_javascript技巧

前言 其实回调函数简单通俗点就是当有a和b两个函数,当a作为参数传给b,并在b中执行,这时a就是一个回调(callback)函数,如果a是一个匿名函数,则为匿名回调函数那下面们来通过一个实例来具体解释下Javascript回调函数怎么使用. 实例 在很久很久以前,有一个人. var person; 他是个人,也就是一个对象. person= {}; // 在JavaScript中,花括号就代表是一个对象 他有个名字叫小明. person.name = '小明'; 看一下是不是真的叫小明. ale

[译] JavaScript 中的 CSS:基于组件的样式的未来

本文讲的是[译] JavaScript 中的 CSS:基于组件的样式的未来, 原文地址:CSS in JavaScript: The future of component-based styling 原文作者:Jonathan Z. White 译文出自:掘金翻译计划 译者:bambooom 校对者:Aladdin-ADD.reid3290 JavaScript 中的 CSS:基于组件的样式的未来 使用行内样式使我们可以获得 JavaScript 的所有编程支持.这让我们获得类似 CSS 预处

理解javascript 回调函数

在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A.我们就说函数A叫做回调函数.如果没有名称(函数表达式),就叫做匿名回调函数.因此callback 不一定用于异步,一般同步(阻塞)的场景下也经常用到回调,比如要求执行某些操作后执行回调函数. 例子 一个同步(阻塞)中使用回调的例子,目的是在func1代码执行完成后执行func2. var func1=function(callback){     //do something

JavaScript回调(callback)函数概念自我理解及示例

此文适合JavaScript入门级选手阅读,高手就可以飘过了. 先扯点闲话.在中国,有这么一种现象:不管什么词或者概念,总会有些 人把这些东西解释的神乎其神,貌似搞得别人听不懂就觉得自己很厉害的样子.其实不知道有多2.我个人比较崇尚简洁明了.什么词,什么概念,如果你能用简短 的一两句话让大家听明白,这才是本事.好了,闲话不扯了,进入正题. 在JavaScript里什么叫Callback"回调函数",用我的话来讲就是把方法b当做一个参数传递个方法a,当方法a执行完后执行另外一个指定函数(