JavaScript回调函数的理解

回调函数的理解

function add(x,y,callback){
    console.log(1)
    setTimeout(function(){
        var ret = x+y;
        // return ret
        callback(ret)
    },1000)
}

console.log(add(10,20,function(ret){
    console.log(ret)
}))

//返回结果
//1
//undefined
//30
  • 要分析上面的结果首先我们需要对JavaScript的执行机制有一定的了解
    • JavaScript是一门单线程语言,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
        如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。
        JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
        于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
        在这里插入图片描述
        1、同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
        2、当Event Table中指定的事情完成时,会将这个函数移入Event Queue。
        3、主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
        4、上述过程会不断重复,也就是常说的Event Loop(事件循环)。
        5、我们不禁要问了,那怎么知道主线程执行栈为空啊?js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。
  • 有了上面的对JavaScript的执行机制的理解现在我们回过头来看程序

在这里插入图片描述
所以此处理解为,回调函数(callback)因为setTimeout的存在变成了一个异步执行的函数,需要等到主线程中的任务执行完后才从Event Queue中调出执行。
为什么这么说呢?看如下代码

function add(x,y,callback){
    console.log(1)   
        var ret = x+y;
        // return ret
        callback(ret) 
}

console.log(add(10,20,function(ret){
    console.log(ret)
}))
//执行结果
//1
//30
//undefined

也就是说,要有响应的异步请求和回调函数绑定才能发挥它的用处
可能说得有点懵,下面不妨通过一个实例来说明一下

//在router.js中
//编辑学生
 var Students = require('./student')
 var router = express.Router()
 
router.get('/students/edit',function(req,res){
    Students.editById(req.query.id,function(err,stu){
        if(err){
            res.status(500).send('Server no connected')
        }
        res.render('edit.html',{
            students:stu
        })
    })
})

//在student.js中
// 编辑学生
exports.editById = function(student,callback){
    fs.readFile(dbPath,'UTF-8',function(err,data){
        if(err){
            return callback(err)
        }
        var students = JSON.parse(data).stud
        var stu = students.find(function(item){
            return item.id ==student
        })
        callback(null,stu);  
    })
}
  • 这里例子中用了两次异步请求,说到这里可以回头品味一下这段话
    • JavaScript是一门单线程语言,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
        如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。
        JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
  • 因此这里的回调函数就是把IO设备的结果返回
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值