一. 问题背景
在我们编写js代码时,有时会遇到这样的问题:循环执行内部异步请求函数,将得到的值加入到列表中。 结果出人意料,console.log显示列表值竟然为空,这是js的一大特性,与我们平时用的后端语言java C# python等区别略大。 导致问题的根本所在就是线程问题,JS是单线程的,而后端语言是多线程的。
表象来讲,单线程:同一个时间只能做一件事。多线程:同一时间,可以做多件事。
js的单线程并不是说只有一个线程,而是执行代码的线程只有一个,称为主线程。那么当初为什么设计成单线程呢,这也与B/S交互问题有关,如果是多线程会出现交互混乱。
二.同步和异步
回顾问题,我们看到执行中有异步请求函数,与之对应的是同步。同步和异步的区别简单来说就是,比如 我们要计算一个值,同步就是等计算完这个值我才能继续执行下边的代码; 而异步就是我先不等他,我继续执行,放一个闹铃,计算完成后提醒我完成了,然后我再插一脚执行对计算值的处理函数。
三.任务队列
js单线程问题,也就是说执行要按顺序来,那么是什么顺序呢,这就提到另一个东西,叫任务队列,队列即先进先出表,也就是排队的地方,那么具体怎么排呢 , 执行机制是这样的: 主线程会优先执行同步任务,异步任务得到请求后的处理事件进入任务队列,需要注意的是异步完成后也并不是立即执行,而是等到主线程把同步任务执行完,再按异步的排队顺序,执行异步的回调处理。而我们问题的所在就是console.log属于同步任务,也就是说异步请求的列表值还没添上呢就执行了console.log。
四.解决方法
常见解决方法就是构造回调函数, 最常用的方式就是BOM中的定时器函数,这个函数也很特殊,他是属于另一个线程操作的,也就是说设定时间到达之后,才把console.log设为同步任务为主线程执行,那么当设定一段时间后,异步也执行完了,此时也就有了结果。
我自己使用过程中,发现这个问题在请求函数的回调中,设计判断函数,比如列表长度等于 自己需要的长度时再console.log,也能解决问题,这种就属于特定问题特定解决了,更通用的方法还是构造自定义回调函数。
对于现在的js es还有很多方式,无一例外就是构造回调,自行百度其他方法
网友评论