读《你不知道的JavaScript 中》-异步【1】了解概念
一直都知道JS里的异步是很重要的知识点,也知道面试必问,但之前只看过面经,死记硬背了一些概念,感觉还是无法彻底吸收这个知识点,所以就决定好好研究一下到底为什么需要异步,异步又到底是什么概念,在什么情形下需要用异步,并且如何用?
决定系统学习前端的第一天,刚好读到了《你不知道的JavaScript 中》的电子版159页——异步,就希望借此博客作为自己的读后感,认真做好总结,希望能对异步有个清晰的认知,而不是单纯背面经,接下来开始陈述我的感悟。
开篇点题:程序中现在运行的部分和将来即将运行的部分之间的关系即异步编程的核心。
1.了解概念
在某一些情形下,下一行代码的执行并不一定在上一行代码执行后就可以执行,比如:
----------------------------------------------
var data = ajax('a-url';);
console.log(data);
//data是不会包含ajax结果的
----------------------------------------------
由于ajax请求不是同步完成的,就意味着第一行语句出现在第二行语句之前,但是执行到第二行语句时第一行语句还没执行完,所以data没有办法获得数据值。那么怎样才能按照我们的预期来得到data值呢?如果ajax(...)能一直阻塞直到接收到响应数据返回,那么第二行语句就能够成功打印出data了。对应的代码解决方法就是简单粗暴的一个回调函数,格式如下:
----------------------------------------------
ajax('a-url', function myCallbackFunction(data) {
console.log(data);//这样使用回调函数可以得到数据
});
----------------------------------------------
之所以上述做法可行,是因为发出ajax请求获取要求从服务器获取数据时,提前在回调函数中设置响应代码,然后JavaScript引擎会通知宿主环境:回调函数先暂停执行,一旦完成了网络请求拿到数据后,就调用该回调函数。而关于回调函数为何能成功地在获取数据后执行,就涉及到事件循环队列eventloop的概念,当注意:setTimeout()并没有把回调函数放在事件循环队列中,所做的是设定定时器,当时间到了,环境就会把回调函数放在事件循环中,在接下来的某个时刻就会执行这个回调。
如果在setTimeout()到时后,eventloop中还剩其余未执行的事件,那么setTimeout()中的回调就会等到eventloop为空了后再执行,所以实际上,用setTimeout()来定时精度不高,只能确保它的回调函数不会在规定的时间之前执行,但不保证一定在闹铃响的时候执行,可能在那之后,要先判断eventloop是否为空。
任务队列和事件循环队列eventloop有什么不同呢?队伍队列其实是eventloop的每个tick之后的一个队列,在事件循环的每个tick中,异步动作不会导致一个完整的新事件被添加到事件循环队列中,而是会在当前tick的任务队列末尾加一个任务,所以二者的关系是:eventloop中的一个事件可能会导致在当前事件的任务队列添加一个任务。