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


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

回调  —— 题图来自 unsplash前端

回调是什么?

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

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

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

为何咱们须要回调?

有一个很是重要的缘由 —— JavaScript 是事件驱动的语言。这意味着,JavaScript 不会由于要等待一个响应而中止当前运行,而是在监听其余事件时继续执行。来看一个基本的例子:android

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

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

first();
second();复制代码

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

// 1
// 2复制代码

一切都如此美好。git

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

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() 语句来区分请求是否成功,而后相应地处理新数据。

你作到了

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


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOSReact前端后端产品设计 等领域,想要查看更多优质译文请持续关注 掘金翻译计划

相关文章
相关标签/搜索