博客地址:https://ainyi.com/96
眾所周知,JavaScript 是單線程的,但異步在 js 中很常見,那么簡單來介紹一下異步編程
同步編程和異步編程
同步編程,計算機一行一行按順序依次執行代碼,當前代碼任務執行時會阻塞后續代碼的執行;典型的請求-響應模型就是這樣,當請求調用一個函數或方法后,需等待其響應返回,然后執行后續代碼
異步編程,執行當前任務時(執行中),也可直接執行下一個任務;多個任務並發執行
這就涉及到兩個比較容易混淆的概念了:並行 和 並發
並行(parallel):指同一時刻內多任務同時進行;如下圖:
並發(concurrency):指在同一時間段內,多任務同時進行着,但是同一時刻,只有某一任務執行。使得在宏觀上具有多個進程同時執行的效果,但在微觀上只是把時間分成若干段,使多個進程快速交替地執行;如下圖:
異步機制
由上面並發的解釋,可以知道單線程可以實現類似多線程機制的這種執行方式;那么 JavaScript 單線程的異步編程可以實現多任務並發執行
重點實現 js 異步的方式,就是事件循環,之前寫過關於事件循環的例子,可看:JavaScript 事件循環、異步和同步
事件循環
事件循環涉及到兩個概念:消息隊列、任務
消息隊列:也叫任務隊列,存儲待處理消息及對應的回調函數或事件處理程序
任務:js 區分同步任務和異步任務,代碼執行就是在執行任務,也就是對應同步和異步的代碼塊
首先 JavaScript 的同步任務是進入主線程的執行棧執行;異步任務則進入消息隊列(任務隊列),一個存儲着待執行任務的隊列,嚴格按照時間先后順序執行,排在隊頭的任務將會率先執行,而排在隊尾的任務會最后執行
事件循環的流程:檢查主線程執行棧是否為空,先執行執行棧中的同步任務,異步任務(回調函數)放入任務隊列中,一旦執行棧中的所有的同步任務執行完畢,就會取出任務隊列的首部壓入執行棧,開始執行,然后繼續檢查執行棧是否為空,重復這個過程
簡單來說:事件循環其實就是入棧出棧的循環
這樣就能實現異步方式
js 的異步方式
- setTimeout
- ajax
- Promise
- Generator
setTimeout
即使將時間設置為 0,也會延遲執行,即異步執行。具體可看:setTimeout 時間參數為 0 的探討
setTimeout(() => {
console.log('Hello!')
}, 0)
ajax
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()
xhr.open 中第三個參數默認為 false 異步執行,改為 true 時為同步執行
Promise
promise 就經常使用了,平常使用 axios 作為請求接口的方式,就是封裝了 Promise。當然也可以自己封裝使用
具體可看:ES6 Promise 解析及詳解三個狀態
const promise = new Promise(resolve => {
setTimeout(() => {
resolve('hello')
}, 1000)})
promise.then(value => {
console.log(value, 'world')
}, error =>{
console.log(error, 'unhappy')
})
Generator
generator 也叫做生成器,它是 ES6 中引入的一種新的函數類型,內部擁有能夠多次啟動和暫停代碼執行的強大能力,那么也能夠用於異步編程中
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)
})
博客地址:https://ainyi.com/96