- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章一篇文章看懂JavaScript中的回调由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
回调函数是每个前端程序员都应该知道的概念之一。回调可用于数组、计时器函数、promise、事件处理中.
本文将会解释回调函数的概念,同时帮你区分两种回调:同步和异步.
首先写一个向人打招呼的函数.
只需要创建一个接受 name 参数的函数 greet(name)。这个函数应返回打招呼的消息:
1
2
3
4
5
|
function
greet(name) {
return
`Hello, ${name}!`;
}
greet(
'Cristina'
);
// => 'Hello, Cristina!'
|
如果向很多人打招呼该怎么办?可以用特殊的数组方法 array.map() 可以实现:
1
2
3
4
|
const persons = [
'Cristina'
,
'Ana'
];
const messages = persons.map(greet);
messages;
// => ['Hello, Cristina!', 'Hello, Ana!']
|
persons.map(greet) 获取 persons 数组的所有元素,并分别用每个元素作为调用参数来调用 greet() 函数:greet('Cristina'), greet('Ana').
有意思的是 persons.map(greet) 方法可以接受 greet() 函数作为参数。这样 greet() 就成了回调函数.
persons.map(greet) 是用另一个函数作为参数的函数,因此被称为高阶函数.
回调函数作为高阶函数的参数,高阶函数通过调用回调函数来执行操作.
重要的是高阶函数负责调用回调,并为其提供正确的参数.
在前面的例子中,高阶函数 persons.map(greet) 负责调用 greet() 函数,并分别把数组中所有的元素 'Cristina' 和 Ana ' 作为参数.
这就为识别回调提供了一条简单的规则。如果你定义了一个函数,并将其作参数提供给另一个函数的话,那么这就创建了一个回调.
你可以自己编写使用回调的高阶函数。下面是 array.map() 方法的等效版本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
function
map(array, callback) {
const mappedArray = [];
for
(const item of array) {
mappedArray.push(
callback(item) );
}
return
mappedArray;
}
function
greet(name) {
return
`Hello, ${name}!`;
}
const persons = [
'Cristina'
,
'Ana'
];
const messages = map(persons, greet);messages;
// => ['Hello, Cristina!', 'Hello, Ana!']
|
map(array, callback) 是一个高阶函数,因为它用回调函数作为参数,然后在其主体内部调用该回调函数:callback(item).
注意,常规函数(用关键字 function 定义)或箭头函数(用粗箭头 => 定义)同样可以作为回调使用.
回调的调用方式有两种:同步和异步回调.
同步回调是“阻塞”的:高阶函数直到回调函数完成后才继续执行.
例如,调用 map() 和 greet() 函数.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
function
map(array, callback) {
console.log(
'map() starts'
);
const mappedArray = [];
for
(const item of array) { mappedArray.push(callback(item)) }
console.log(
'map() completed'
);
return
mappedArray;
}
function
greet(name) {
console.log(
'greet() called'
);
return
`Hello, ${name}!`;
}
const persons = [
'Cristina'
];
map(persons, greet);
// logs 'map() starts'
// logs 'greet() called'
// logs 'map() completed'
|
其中 greet() 是同步回调.
同步回调的步骤:
同步回调的例子 。
许多原生 JavaScript 类型的方法都使用同步回调.
最常用的是 array 的方法,例如:array.map(callback), array.forEach(callback), array.find(callback), array.filter(callback), array.reduce(callback, init) 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// Examples of synchronous callbacks on arrays
const persons = [
'Ana'
,
'Elena'
];
persons.forEach(
function
callback(name) { console.log(name);
}
);
// logs 'Ana'
// logs 'Elena'
const nameStartingA = persons.find(
function
callback(name) {
return
name[0].toLowerCase() ===
'a'
;
}
);
nameStartingA;
// => 'Ana'
const countStartingA = persons.reduce(
function
callback(count, name) { const startsA = name[0].toLowerCase() ===
'a'
;
return
startsA ? count + 1 : count;
},
0
);
countStartingA;
// => 1
|
字符串类型的 string.replace(callback) 方法也能接受同步执行的回调:
1
2
3
4
5
6
7
8
|
// Examples of synchronous callbacks on strings
const person =
'Cristina'
;
// Replace 'i' with '1'
person.replace(/./g,
function
(char) {
return
char.toLowerCase() ===
'i'
?
'1'
: char;
}
);
// => 'Cr1st1na'
|
异步回调是“非阻塞的”:高阶函数无需等待回调完成即可完成其执行。高阶函数可确保稍后在特定事件上执行回调.
在以下的例子中,later() 函数的执行延迟了 2 秒:
1
2
3
4
5
6
7
8
9
|
console.log(
'setTimeout() starts'
);
setTimeout(
function
later() {
console.log(
'later() called'
);
}, 2000);
console.log(
'setTimeout() completed'
);
// logs 'setTimeout() starts'
// logs 'setTimeout() completed'
// logs 'later() called' (after 2 seconds)
|
later() 是一个异步回调,因为 setTimeout(later,2000) 启动并完成了执行,但是 later() 在 2 秒后执行.
异步调用回调的步骤:
异步回调的例子 。
计时器函数异步调用回调:
1
2
3
4
5
6
7
8
9
|
setTimeout(
function
later() {
console.log(
'2 seconds have passed!'
);
}, 2000);
// After 2 seconds logs '2 seconds have passed!'
setInterval(
function
repeat() {
console.log(
'Every 2 seconds'
);
}, 2000);
// Each 2 seconds logs 'Every 2 seconds!'
|
DOM 事件侦听器还异步调用事件处理函数(回调函数的子类型):
1
2
3
4
5
6
|
const myButton = document.getElementById(
'myButton'
);
myButton.addEventListener(
'click'
,
function
handler() {
console.log(
'Button clicked!'
);
});
// Logs 'Button clicked!' when the button is clicked
|
在函数定义之前加上特殊关键字 async 会创建一个异步函数:
1
2
3
4
5
6
|
async
function
fetchUserNames() {
const resp = await fetch(
'https://api.github.com/users?per_page=5'
);
const users = await resp.json();
const names = users.map(({ login }) => login);
console.log(names);
}
|
fetchUserNames() 是异步的,因为它以 async 为前缀。函数 await fetch('https://api.github.com/users?per_page=5') 从 GitHub 上获取前5个用户 。然后从响应对象中提取 JSON 数据:await resp.json().
异步函数是 promise 之上的语法糖。当遇到表达式 await <promise> (调用 fetch() 会返回一个promise)时,异步函数会暂停执行,直到 promise 被解决.
异步回调函数和异步函数是不同的两个术语.
异步回调函数由高阶函数以非阻塞方式执行。但是异步函数在等待 promise(await <promise>)解析时会暂停执行.
但是你可以把异步函数用作异步回调! 。
让我们把异步函数 fetch UserNames() 设为异步回调,只需单击按钮即可调用:
1
2
3
|
const button = document.getElementById(
'fetchUsersButton'
);
button.addEventListener(
'click'
, fetchUserNames);
|
回调是一个可以作为参数传给另一个函数(高阶函数)执行的函数.
回调函数有两种:同步和异步.
同步回调是阻塞的.
异步回调是非阻塞的.
最后考考你:setTimeout(callback,0) 执行 callback 时是同步还是异步的?
到此这篇关于JavaScript中回调的文章就介绍到这了,更多相关JavaScript的回调内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://mp.weixin.qq.com/s/zqDy3ZjIKTK-9Mg7FjWLnA 。
最后此篇关于一篇文章看懂JavaScript中的回调的文章就讲到这里了,如果你想了解更多关于一篇文章看懂JavaScript中的回调的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在研究 learnyounode 的 HTTP 客户端作业。 我想知道为什么控制台记录来自response.on(“end”,callback)的数据仅输出预期输出的最后一部分,而控制台记录来自r
我正在尝试创建一个对象列表(在我的示例中为 List),我在其中使用 json 将对象添加到此列表,但该列表仍为空。这是我的代码: public List readCardsFromJson() {
我有一个 JavaScript 函数“print_something”,它在大约 300 个 jsp 帮助页面中实现。我发现这个“print_something”函数必须被纠正。所以我正在寻找一个不更
有 2 个 HTML 下拉列表,一个用于 12 小时时间,一个用于每小时 5 分钟的时间间隔。 .. 1 .. 12 .. 0 .. 55 .. 一直在尝试使用 if/
我有一个 A 类,我打算在它与设备驱动程序交互时将其放入共享库中。 我有一个 B 类,将来可能是 C、D、E...,它将使用共享库中的 A 类。 我想要在类 A 中设置回调函数的功能,以便当特定事件发
我需要能够在处理完 Observable.next() 之后执行回调。 我有一个组件“A”,它有一个主题使用 Subject.next() 发送通知。我有一个组件“B”,它订阅了 Subject.as
我有一张在顶部和底部单元格下方带有阴影的表格(此处使用 Matt Gallagher 的解决方案:http://cocoawithlove.com/2009/08/adding-shadow-effe
有人可以向我解释一下为什么这段代码有效 renderSquare(i) { return ( this.handleClick(i)} /> ); } 但
我可以让两个不同的客户端监听相同的 WCF 回调并让它们都接收相同的数据而不必进行两次处理吗? 最佳答案 不是真的 - 至少不是直接的。你所描述的听起来很像发布/订阅模式。 WCF 服务基本上在任何给
我是 SignalR 的新手,如果这个问题太明显,我深表歉意,但我在文档中找不到任何答案。 这是我的代码。 /*1*/ actions.client.doActionA = function (r
我有这个应用程序,您可以在其中输入一些文本并按下一个按钮,将此文本添加到自定义小部件中。这是代码: import 'dart:core'; import 'package:flutter/materi
我读到当您还想使用模型回调时不能使用 Keras 进行交叉验证,但是 this post表明这毕竟是可能的。但是,我很难将其纳入我的上下文。 为了更详细地探讨这个问题,我正在关注 machinelea
我尝试在重力表单中提交表单失败后运行一些 jQuery 代码,也就是验证发现错误时。 我尝试使用 Ajax:complete 回调,但它根本不触发。 我尝试运行的代码基本上将监听器添加到选择下拉列表中
我有一个 $image,我 .fadeIn 和 .fadeOut,然后 .remove .fadeOut 完成。这是我的代码: $image .fadeIn() .fadeOut(func
我正在处理一个自定义文件路径类,它应该始终执行一个函数 写入相应的系统文件及其文件对象后 关闭。该函数将文件路径的内容上传到远程位置。 我希望上传功能完全在用户的幕后发生 透视,即用户可以像使用其他任
这里是 javascript 新手,所以回调在我的大脑中仍然有点不确定。 我想做的是:给定一个“菜单”,它是一个 objectId 数组,查询与该 objectId 相对应的每个 foodItem,获
我正在学习回调,我编写了以下代码: var http = require('http'); var str = ""; var count = 2; function jugglingAsync(ca
这是我的困境,我有一系列被调用的函数,我正在使用回调函数在它们完成时执行函数。回调返回一个值并且效果也很好,我的问题是当我向回调添加参数时我无法再访问返回值。这是一个有效的例子: function m
This question already has answers here: Explanation of function pointers (4个答案) 上个月关闭。 如何将函数指针作为参数传递
我无法让以下代码工作。假设 ajax 调用有效,并且 msg['username'] 预设为 'john'。我想我对如何将变量传递给回调感到困惑。编辑:我认为我的主要困惑是如何从 Ajax 中获取“m
我是一名优秀的程序员,十分优秀!