1.回调函数(callback)
1.1回调函数实现机制是什么?
首先声明回调函数不是异步函数,它和异步函数没有直接的联系,回调函数只是异步函数的一种实现方式 回调函数的实现机制是:在一个A函数里面将一个B函数当作参数传入,并且在A函数里面调用B函数
function A(callback){
console.log('我是A函数,我调用了B函数')
return callback();
}
function B(){
console.log('我是B函数,我被A函数调用了')
}
A(B);
2.回调函数和闭包
2.1作用域链以及执行上下文
1.执行上下文:简单来说就是作用域范围,块级作用域中,执行上下文就是块级作用域里面的内容(不包括块级作用域里面的块级作用域) 2.作用域链:作用域链定义了当变量在当前上下文访问不到的时候如何沿作用域链继续查询的一套规则,只能由内嵌的执行上下文去寻找包裹着它的执行上下文,直到找到全局执行上下文之后才会停止(查找规则是先查找自己执行上下文中是否有,若没有则往上去找),但是不能由外部执行上下文去寻找内嵌的执行上下文
// obj为全局执行上下文
let obj = 10;
console.log(a); // console.log()调用的变量a没有在全局执行上下文中被定义,根据作用域链的机制,
// 只能由内嵌的执行上下文去寻找包裹着它的执行上下文,
// 而不允许外部执行上下文执行寻找内嵌在其内部的执行上下文,
// 所以这里为 a is not defined
// myfn函数为块级执行上下文
function myfn(){
let a = 10; // a变量被定义在块级执行上下文myfn中
console.log(obj); // obj在块级作用域中是没有被定义的,但是根据作用域链的机制,
// 全局作用域定义了obj变量,则返回10
}
2.2回调函数和闭包的区别
1.按照作用域链的机制,就会出现一个问题,就是外部执行上下文始终是获取不到内嵌执行上下文的变量的,正因为这样所以出现了闭包,闭包就是打破正常作用域链的机制,使外部执行上下文可以获取到内嵌执行上下文的变量值 2.回调函数则是将一个函数当作参数传入到另一个函数中,且被执行
// 闭包
function myfn(){
let a = 10;
function fn(){
let b = 20;
return b; // 这里的return 相当于把变量b 的作用域提升了一级,到外部myfn作用域里去了
}
a = fn(); // 这里相当于访问到了 内嵌块级作用域的变量b
console.log(a) // 20;
}
myfn();
// 回调函数
function A(callback){
console.log('我是A函数,我调用了B函数')
return callback();
}
function B(){
console.log('我是B函数,我被A函数调用了')
}
A(B);
3.利用回调函数实现最简单的异步函数
3.1异步函数的介绍
1.JS执行过程中会碰到两种执行方式一种是“同步执行(Synchronous execution)”,另一种方法是“异步执行(Asynchronous execution)”,同步任务是JS代码从上到下依次进行执行(从前到后依次进行打饭,碰到打饭纠结者则等待他纠结完成打完饭之后再进行下一个打饭),异步任务则是JS代码依旧从上到下依次执行(从前到后依次打饭),但是碰到打饭纠结的人,JS就会叫他去纠结窗口等待打饭,之后让所有正常打饭的人(所以同步任务)先打饭,当正常打饭的人打完饭了(所用同步任务执行完毕),就可以让纠结窗口排队的人依次进行打饭(依次执行异步任务) 2.异步函数需要搭配回调函数来使用
3.2异步函数的好处
1.基于JavaScript是单线程的一种脚本语言,执行效率当然是令人堪忧的,因为它只会单纯的一条路走到黑,也就是不管文件多大,都得等它执行完成才能继续执行后面部分的代码,这个时候就会出现阻塞的情况,也就是页面可能一直在加载,半天没响应,导致客户使用起来很不满意 2.异步函数的好处:异步函数就很好的解决了这个阻塞情况,让客户使用起来感觉更加流畅,好感度增加
3.3最简单的异步函数的实现
// 利用setTimeout来实现最简单的一个异步函数的实现
console.log(1); // 同步任务,打印1
setTimeout(function(){ // 等全部同步任务执行后,在等3秒才会打印 2
console.log(2);
},3000)
console.log(3);// 同步任务,打印3
/* 执行顺序
1
3
2
*/
// 以上代码并不好,因为不便于重新检查代码,
// 利用以下代码(与上面代码效果是一样的)会使逻辑更加清晰,也方便检查
function showTwo(){
console.log(2);
}
console.log(1);
setTimeout(showTwo,3000);
console.log(3);
4.普通回调函数的缺陷:回调地狱(callback hell)
串联多个异步操作是一个常见的问题,通常需要深度嵌套的回调函数(俗称“回调地狱”)来解决。也就是说嵌套代码多了,就会将代码横向排列。随着代码越来越复杂,普通回调策略是不具有扩展性的。
function myfn(){
return function myfn1(){
return function myfn2(){
return function myfn3(){
// ...
}