请稍候,加载中....

JavaScript 异步编程

异步的概念

异步(Asynchronous, async)是与同步(Synchronous, sync)相对的概念。

在我们学习的传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系。

简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高。

以上是关于异步的概念的解释,接下来我们通俗地解释一下异步:异步就是从主线程发射一个子线程来完成任务。

 


异步编程场景

如果程序中有一些操作需要很长时间,比如服务器有一个请求响应比较耗时,而其他步骤可以在等待这些操作的时候同时执行,那么这时候就可以使用异步编程。

现在有一个按钮,如果我们设置它的 onclick 事件为一个死循环,那么当这个按钮按下,整个网页将失去响应。

为了避免这种情况的发生,我们常常用子线程来完成一些可能消耗时间足够长以至于被用户察觉的事情,比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。但是子线程有一个局限:一旦发射了以后就会与主线程失去同步,我们无法确定它的结束,如果结束之后需要处理一些事情,比如处理来自服务器的信息,我们是无法将它合并到主线程中去的。

为了解决这个问题,JavaScript 中的异步操作函数往往通过回调函数来实现异步任务的结果处理。

 


回调函数

回调函数就是一个函数,它是在我们启动一个异步任务的时候就告诉它:等你完成了这个任务之后要干什么。这样一来主线程几乎不用关心异步任务的状态了,异步任务一旦完成就会自动执行回调函数。

回调函数实例

<body>
   <div id="demo"></div>
</body>
<script>
var n = 0
function print() { 
    if (n < 50){
       document.getElementById("demo").innerHTML = n
       setTimeout(print, 100);
       n += 1
       return
    }
    document.getElementById("demo").innerHTML="每一次让人叹慕的变化,都是长期汗水的升华!";
}
setTimeout(print, 1000);
document.write("主线程继续执行!")
</script>

这段程序中的 setTimeout 就是一个消耗时间较长(3 秒)的过程,它的第一个参数是个回调函数,第二个参数是毫秒数,这个函数执行之后会产生一个子线程,子线程会等待0.1秒,然后执行回调函数 "print"。

注意:既然 setTimeout 会在子线程中等待 3 秒,在 setTimeout 函数执行之后主线程并没有停止, 主线程将继续执行

 


异步 AJAX

除了setTimeout 函数以外,异步回调广泛应用于 AJAX 编程。

javascript提供的XMLHttpRequest对象支持异步加载。

异步加载实例

<script src="/static/js/jquery-3.4.1.min.js?ver=1.1" type="text/javascript" charset="utf-8"></script>

<script>
$.get("https://www.python-xp.com/article/view/372",function(data,status){ 
  document.write("加载数据量: " + data.length + "<br>状态: " + status); });
</script>

 


Python学习手册-