<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>异步编程 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/</link><description>Recent content in 异步编程 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 08 Nov 2024 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B/index.xml" rel="self" type="application/rss+xml"/><item><title>异步编程</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/</guid><description>&lt;p&gt;浏览器中的JavaScript程序是典型的事件驱动型程序，即它们会等待用户触发后才真正的执行，而基于的JavaScript的服务器通常要等待客户端通过网络发送请求，然后才能执行。这种异步编程在JavaScript是很常见的，下面就来介绍几个异步编程的重要特性，它们可以使编写异步代码更容易。&lt;/p&gt;
&lt;p&gt;本文将按照异步编程方式的出现时间来归纳整理： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-013/image-01.webp"&gt;&lt;/p&gt;
&lt;h2 id="一什么是异步"&gt;一、什么是异步&lt;/h2&gt;
&lt;p&gt;下面先来看看同步和异步的概念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同步：&lt;/strong&gt; 在执行某段代码时，在没有得到返回结果之前，其他代码暂时是无法执行的，但是一旦执行完成拿到返回值，即可执行其他代码。也就是说，在此段代码执行完未返回结果之前，会阻塞之后的代码执行，这样的情况称为同步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步：&lt;/strong&gt; 当某一代码执行异步过程调用发出后，这段代码不会立刻得到返回结果。而是在异步调用发出之后，一般通过回调函数处理这个调用之后拿到结果。异步调用发出后，不会影响阻塞后面的代码执行，这样的情况称为异步。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面来看一个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 同步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;syncAdd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;syncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 立即得到结果：3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 异步
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  &lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;    &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;  }, &lt;span style="color:#ae81ff"&gt;1000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;) &lt;span style="color:#75715e"&gt;// 1s后打印结果：3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里定义了同步函数 syncAdd 和异步函数 asyncAdd，调用 syncAdd(1, 2) 函数时会等待得到结果之后再执行后面的代码。而调用 asyncAdd(1, 2) 时则会在得到结果之前继续执行，直到 1 秒后得到结果并打印。&lt;/p&gt;
&lt;p&gt;我们知道，JavaScript 是单线程的，如果代码同步执行，就可能会造成阻塞；而如果使用异步则不会阻塞，不需要等待异步代码执行的返回结果，可以继续执行该异步任务之后的代码逻辑。因此，在 JavaScript 编程中，会大量使用异步。&lt;/p&gt;
&lt;p&gt;那为什么单线程的JavaScript还能实现异步呢，其实也没有什么魔法，只是把一些操作交给了其他线程处理，然后采用了&lt;strong&gt;事件循环&lt;/strong&gt;的机制来处理返回结果。&lt;/p&gt;
&lt;h2 id="二回调函数"&gt;二、回调函数&lt;/h2&gt;
&lt;p&gt;在最基本的层面上，JavaScript的异步编程式通过回调实现的。回调的是函数，可以传给其他函数，而其他函数会在满足某个条件时调用这个函数。下面就来看看常见的不同形式的基于回调的异步编程。&lt;/p&gt;
&lt;h3 id="1-定时器"&gt;1. 定时器&lt;/h3&gt;
&lt;p&gt;一种最简单的异步操作就是在一定时间之后运行某些代码。如下面代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;setTimeout&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;asyncAdd&lt;/span&gt;(&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;, &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;), &lt;span style="color:#ae81ff"&gt;8000&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;setTimeout()&lt;/code&gt;方法的第一个参数是一个函数，第二个参数是以毫秒为单位的时间间隔。&lt;code&gt;asyncAdd()&lt;/code&gt;方法可能是一个回调函数，而&lt;code&gt;setTimeout()&lt;/code&gt;方法就是注册回调函数的函数。它还代指在什么异步条件下调用回调函数。&lt;code&gt;setTimeout()&lt;/code&gt;方法只会调用一次回调函数。&lt;/p&gt;
&lt;h3 id="2-事件监听"&gt;2. 事件监听&lt;/h3&gt;
&lt;p&gt;给目标 DOM 绑定一个监听函数，用的最多的是 &lt;code&gt;addEventListener&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;document.&lt;span style="color:#a6e22e"&gt;getElementById&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;#myDiv&amp;#39;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;我被点击了&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过给 id 为 &lt;code&gt;myDiv&lt;/code&gt; 的一个元素绑定了点击事件的监听函数，把任务的执行时机推迟到了点击这个动作发生时。此时，&lt;strong&gt;任务的执行顺序与代码的编写顺序无关，只与点击事件有没有被触发有关&lt;/strong&gt;。&lt;/p&gt;</description></item></channel></rss>