JavaScript 异步编程
<p>博客地址:https://ainyi.com/96</p><p>众所周知,JavaScript 是单线程的,但异步在 js 中很常见,那么简单来介绍一下异步编程</p>
<h2 id="同步编程和异步编程">同步编程和异步编程</h2>
<p><strong>同步编程</strong>,计算机一行一行按顺序依次执行代码,当前代码任务执行时会阻塞后续代码的执行;典型的请求-响应模型就是这样,当请求调用一个函数或方法后,需等待其响应返回,然后执行后续代码</p>
<p><strong>异步编程</strong>,执行当前任务时(执行中),也可直接执行下一个任务;多个任务并发执行</p>
<p>这就涉及到两个比较容易混淆的概念了:<strong>并行</strong> 和 <strong>并发</strong></p>
<p><strong>并行(parallel)</strong>:指同一时刻内多任务同时进行;如下图:<br>
<img src="https://ainyi.com/upload/content/96/7557373-72912ea8e89c4007.jpg"></p>
<br>
<p><strong>并发(concurrency)</strong>:指在同一时间段内,多任务同时进行着,但是同一时刻,只有某一任务执行。使得在宏观上具有多个进程同时执行的效果,但在微观上只是把时间分成若干段,使多个进程快速交替地执行;如下图:<br>
<img src="https://ainyi.com/upload/content/96/7557373-da64ffd6d1effaac.jpg"></p>
<h2 id="异步机制">异步机制</h2>
<p>由上面并发的解释,可以知道单线程可以实现类似多线程机制的这种执行方式;那么 JavaScript 单线程的异步编程可以实现多任务<mark>并发执行</mark></p>
<p>重点实现 js 异步的方式,就是<mark>事件循环</mark>,之前写过关于事件循环的例子,可看:JavaScript 事件循环、异步和同步</p>
<h3 id="事件循环">事件循环</h3>
<p>事件循环涉及到两个概念:消息队列、任务</p>
<p><strong>消息队列</strong>:也叫任务队列,存储待处理消息及对应的回调函数或事件处理程序<br>
<strong>任务</strong>:js 区分同步任务和异步任务,代码执行就是在执行任务,也就是对应同步和异步的代码块</p>
<p>首先 JavaScript 的同步任务是进入主线程的执行栈执行;异步任务则进入<mark>消息队列(任务队列)</mark>,一个存储着待执行任务的队列,严格按照时间先后顺序执行,排在队头的任务将会率先执行,而排在队尾的任务会最后执行</p>
<p>事件循环的流程:<strong>检查主线程执行栈是否为空,先执行执行栈中的同步任务,异步任务(回调函数)放入任务队列中,一旦执行栈中的所有的同步任务执行完毕,就会取出任务队列的首部压入执行栈,开始执行,然后继续检查执行栈是否为空</strong>,重复这个过程</p>
<p><img src="https://ainyi.com/krryblog/upload/content/50/28.jpg"></p>
<p>简单来说:事件循环其实就是入栈出栈的循环</p>
<p>这样就能实现异步方式</p>
<h2 id="js-的异步方式">js 的异步方式</h2>
<ul>
<li>setTimeout</li>
<li>ajax</li>
<li>Promise</li>
<li>Generator</li>
</ul>
<p><strong>setTimeout</strong><br>
即使将时间设置为 0,也会延迟执行,即异步执行。具体可看:setTimeout 时间参数为 0 的探讨</p>
<pre><code class="language-js">setTimeout(() => {
console.log('Hello!')
}, 0)
</code></pre>
<br>
<p><strong>ajax</strong></p>
<pre><code class="language-js">let xhr = new XMLHttpRequest()
xhr.onreadystatechange = function() {
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 ) {
console.log(xhr.responseText)
} else {
console.log( xhr.status)
}
}
xhr.open('GET', 'url', false)
xhr.send()
</code></pre>
<p>xhr.open 中第三个参数默认为 false 异步执行,改为 true 时为同步执行</p>
<br>
<p><strong>Promise</strong><br>
promise 就经常使用了,平常使用 axios 作为请求接口的方式,就是封装了 Promise。当然也可以自己封装使用<br>
具体可看:ES6 Promise 解析及详解三个状态</p>
<pre><code class="language-js">const promise = new Promise(resolve => {
setTimeout(() => {
resolve('hello')
}, 1000)})
promise.then(value => {
console.log(value, 'world')
}, error =>{
console.log(error, 'unhappy')
})
</code></pre>
<br>
<p><strong>Generator</strong><br>
generator 也叫做生成器,它是 ES6 中引入的一种新的函数类型,内部拥有能够多次启动和暂停代码执行的强大能力,那么也能够用于异步编程中</p>
<pre><code class="language-js">const axios = require('axios')
const foo = function () {
return axios({
method: 'GET',
url: 'https://cosmos-alien.com/some.url'
})
}
const main = function *() {
try {
let result = yield foo()
console.log(result)
} catch (err) {
console.error(err)
}
}
let it = main()
let p = it.next().value
p.then((data) => {
it.next(data)
}, (err) => {
it.throw(err)
})
</code></pre>
<p>博客地址:https://ainyi.com/96</p>
</div>
<div id="MySignature" role="contentinfo">
个人博客:https://ainyi.com<br>
GitHub:https://github.com/Krryxa<br><br>
来源:https://www.cnblogs.com/ainyi/p/13673413.html
頁:
[1]