等待jquery加载完成 jquery等待异步完成后执行_非阻塞


多线程

像刚才例子中开多个窗口的方式称为多线程。

线程可以理解成一个应用程序中的执行任务,每个应用程序至少会有一个线程,它被称为主线程。

如果你想实现异步处理,就可以通过开启多个线程,这些线程可以同时执行。

这是异步实现的一种方式。

不过这种方式还是属于阻塞式的。

什么叫做阻塞式呢。你想想,开10个窗口可以满足10个人同时买票。但是现在有100个人呢?不可能再开90个窗口吧,所以每个窗口实际上还是需要排队。

也就是说虽然我可以通过开启多个线程来同时执行很多任务,但是每个任务中的代码仍然是同步的。

当某个任务的代码执行时间过长,也只会影响到当前线程的代码,而其他线程的代码不会受到影响。


等待jquery加载完成 jquery等待异步完成后执行_js异步等待完成后再进行下一步操作_02


单线程非阻塞式

假设现在火车站不想开那么多窗口,还是只有1个窗口提供服务,那如何能够提高购票效率呢?

我们可以这样做,把购票的流程分为两步,第一步:预定及付款。第二步:取票。

其中,第一步可以让购票者在网上操作。第二步到火车站的窗口取票。

这样,最耗时的工作已经提前完成,不需要排队。

到火车站时,虽然只有1个窗口,1次也只能接待1个人,但是取票的动作很快,平均每个人耗时不到1分钟,10个人也就不到10分钟就可以处理完成。

这样既提高了效率,又少开了窗口。这也是一种异步的实现。

我们可以看到,开1个窗口,就相当于只有1个线程。然后把耗时的一些操作分成两部分,先把快速能做完的事情做了,这样保证它不会阻塞其他代码的运行。剩下耗时的部分再单独执行。这就是单线程阻塞式的异步实现机制。


等待jquery加载完成 jquery等待异步完成后执行_js异步等待完成后再进行下一步操作_03


JS中的异步实现

我们知道JS引擎就是以单线程的机制来运行代码。

那么在JS代码中想要实现异步就只有采用单线程非阻塞式的方式。比如下面这段代码:

console.log("start"); setTimeout(function(){ console.log("timeout"); },5000); console.log("end");
这段代码先输出一个字符串"start",然后用时间延迟函数,等到5000秒钟后输出"timeout",在代码的最后输出"end"。最后的执行结果是:
start end //等待5秒后 timeout

从结果可以看到end的输出并没有等待时间函数执行完,实际上setTimeout就是异步的实现。

代码的执行流程是这样的:

首先执行输出字符串"start",然后开始执行setTimeout函数。

由于它是一个异步操作,所以它会被分为两部分来执行,先调用setTimeout方法,然后把要执行的函数放到一个队列中。

代码继续往下执行,当把所有的代码都执行完后,放到队列中的函数才会被执行。

这样,所有异步执行的函数都不会阻塞其他代码的执行。

虽然,这些代码都不是同时执行,但是由于任何代码都不会被阻塞,所以执行效率会很快。


等待jquery加载完成 jquery等待异步完成后执行_字符串_04


大家认真看这个图片,然后思考一个问题:

当setTimeout执行后,什么时候开始计时的呢?

由于单线程的原因,不可能在setTimeout后就开始执行,因为一个线程同一时间只能做一件事情。

执行后续代码的同时就不可能又去计时。

那么只可能是在所有代码执行完后才开始计时,然后5秒后执行队列中的回调函数,是这样吗?我们用一段代码来验证下:

console.log("start"); setTimeout(function(){ console.log("timeout"); },5000); for(let i = 0;i <= 500000;i++){ console.log("i: