回调函数详解 - Kaiqisan
回调函数详解
みんなさんこんにちは、Kaiqisanです、一つの学生プログラマである。今天讲讲异步函数与回调函数有关的东西。
异步函数,它不会马上执行而是会延迟一段时间之后再执行
JavaScript 中常见的异步函数有:setTimeout readFile writeFile ajax readdir
在ES6解决异步函数方法未出现之前,异步函数的运行应与普通的同步函数是隔离开来的,隔离开来的意思是异步函数会等待所有同步函数运行结束之后才会开始执行。这样会导致正常的程序流程被打破,会使某些本该被赋值的一些参数赋值失败。最终导致程序的运行结果并非与理想情况相符合。
let a = 0
setTimeout(() => {
a += 10
}, 1000)
console.log("a的值是" + a) // 最后输出a的值是0
上面的程序执行顺序实际上是这样的
let a = 0 // 第一步,声明,赋初值
console.log("a的值是" + a) // 第二步,打印
setTimeout(() => { // 第三步,延时自加
a += 10
}, 1000)
这样无法达到延时赋值打印的效果。哪怕setTimeout时间是0秒,也会先执行普通代码,再执行定时器。这就是js的单线程 事件循环
下面为传值失败的第二个例子
function dd3(x, y) {
setTimeout(() => {
console.log(x + y)
}, 1000)
}
console.log(dd3(10, 10)) //输出为undefined
console打印是同步函数,它并不等异步函数的执行,直接执行打印操作。
console.log(
setTimeout(() => {
console.log(10 + 10)
}, 1000)
)
由于此时同步函数还未完成(console还未打印),还不允许执行异步的setTimeout方法,所以console里面实际是这样的
console.log()
没错,里面啥也没有,所以打印出来为undefined
但是,如果您需要达到等待一个异步函数执行完成之后再执行后面的程序这样一个目的的话,则需要使用回调函数
这是一个简单的回调函数
function demo(a, b, callback) { // 1
console.log(1)
setTimeout(() => {
var sum = a + b
callback(sum)
}, 3500)
}
demo(10, 200, function(ret) { // 2
console.log(ret)
})
没错,你没有看错,一个函数可以作为一个参数传入!
如果使用一般的方法,程序执行是不会等待异步操作直接输出
如果要获取一个函数异步操作的结果,就必须要用回调函数来获取(里面的数据)
一般情况下,把函数当做参数的目的就是为了获取函数内部的异步获取操作结果,函数的内容是您期望在异步之后延迟执行的方法。
现在开始解析上面的回调函数的每一步流程
1.从整体来说,demo是一个函数,它被声明定义好之后就直接传值执行了。
2.传值之后callback被赋值成为一个函数。
callback = function(ret) { // 2
console.log(ret)
}
3. 完成同步方法,打印一个 1 对应上面的 console.log(1)
4. 此时,同步方法执行完成,开始执行异步的方法。
5.先走进 setTimeout
定时器函数内容,完成a , b的赋值之后,开始执行callback,(一参数如果被赋予一个函数的话后面添加一个括号表示执行操作)
6. 执行callback函数的时候传入参数sum,并被打印,到这里,程序结束。
以上就是一个把同步方法放到异步函数执行完成之后执行的方法(禁止套娃)
总结
异步函数可以真正做到面向程序和顺序的编程,我们可以不用再抱怨:“你妈的为什么,这个程序不是按照我想象中那样执行啊!”,而且,现在ES6,ES7推出了更多针对异步函数执行顺序的方法,但是ES5的这个方法是最基础的,是最应该掌握的,况且,在大家学到node.js的时候,就会发现原生的node.js不支持ES6以上的新规则。回调它不仅是一种方法,也是一种思维,也是一种函数式编程。