作為一門單執行緒的語言,剛學習 JavaScript 語言的時候,我曾懷疑過 JavaScript 在處理 ajax 資料請求,檔案解析等過程效率會很低,而且在執行這些任務較大的程式碼中,會嚴重阻塞後面程式碼的執行。但讓人興奮的是,這門語言具有非同步載入的特性。
事件迴圈
1. 含義
javascript 提供一種機制來處理程式中多個塊的執行,且每個執行塊都呼叫了 JavaScript 引擎,這種機制被稱為事件迴圈。
2. setTimeout
setTimeout 在不清楚它的呼叫機制的時候,可能會容易掉坑。一定要清楚的是,setTimeout 執行的時候,並沒有把回撥函式放入事件迴圈佇列中,它做的事情只是設定一個定時器,當時間到時後,環境才會把回撥函式加入到事件迴圈佇列中
考慮下面的例子
setTimeout(function(){
console.log("setTimeout")
},0)
console.log("console")
// console,setTimeout
複製程式碼
根據 setTimeout 的執行機制,這個例子的先後執行順序就一目瞭然了。即便 setTimeout 的定時器時間為0,但是因為事件迴圈機制,且考慮到瀏覽器實行的延遲作用,setTimeout 依舊還是會慢與外界的 console。
回撥
1.含義
回撥是編寫和處理 JavaScript 程式非同步邏輯最常用的方式。
2.巢狀回撥和鏈式回撥
考慮:
listen('click',function handle(){
setTimeout(function request(){
ajax('http:XXX',function response(data){
if(data.code===200){code...}
else{code...}
})
},
500)
})
複製程式碼
在我初學 javascript 的時候,常寫這種函式巢狀在一起構成一條鏈的程式碼,因為它能按照我們想要執行的順序執行,但是這種程式碼在巢狀多層的時候是很容易讓人混亂的,這種程式碼常常被稱為回撥地獄
不用巢狀將上述程式碼重寫,可寫為:
listen('click',handle)
function handle(){
setTimeout(request,500)
}
function request(){
ajax('http:XXX',response)
}
function response(data){
if(data.code===200){code...}
else{code...}
}
複製程式碼
3.總結
通過上述例子我們可以初步的理解回撥的意義,下面將會講解非同步最常使用的 Promise。
Promise
1.含義
Promise(譯為期望,期待),是一種封裝和組合未來值的易於複用的機制;
2.語法
下面程式碼創造了一個 Promise 例項
const myPromise = new Promise(function(resolve,reject){
// ...code
if(/非同步執行成功/) {
resolve(value)
} else {
//非同步執行失敗
reject(error)
}
複製程式碼
resolve函式的作用是,當 Promise 的狀態由未完成轉變為成功時呼叫的函式,reject函式的作用是,當 Promise 的狀態由未來城轉變為失敗時呼叫的函式 Promise 例項生成後,可以使用 then
方法分別指定 resolved 狀態和 rejected 狀態的回撥函式
myPromise.then(function(value){
// success
},function(error){
//error
}
)
複製程式碼
then
的方法可以接收兩個引數,第一個回到函式是當 Promise 狀態變為成功 resolved 時呼叫,第二個回撥函式是當 Promise 狀態變為失敗 rejected 時呼叫,第二個引數是可選的,非必須的
3.實戰練習
根據上面的事件迴圈機制,以及 Promise 的語法,考慮下方程式碼:
let myPromise = new Promise(function(resolve,reject){
console.log("promise");
resolve()
})
myPromise.then(function(){
console.log("resolved.")
})
console.log("consolelog")
// promise
//consolelog
//resolved.
複製程式碼
上面程式碼中,Promise 新建後立即執行,所以首先輸出的是 “Promise”,然後,then 方法指定回撥函式,將當前指令碼所有同步任務執行完之後再呼叫,所以 ,然後輸出 “consolelog”,最後執行 then ,輸出“resolved."
進而再考慮下面程式碼:
setTimeout(function(){console.log("setTimeout")},0)
let myPromise = new Promise(function(resolve,reject){
console.log("promise");
resolve()
}).then(function(){
console.log("resolved.")
})
console.log("consolelog")
// promise -> consolelog -> resolved. -> setTimeout
複製程式碼
這段程式碼即是上面程式碼加上 setTimeout ,原理是相同的,因為 setTimeout 存在延遲,即便延遲時間為0,它都不屬於 Promise 所在的同步任務事件佇列中,所以,setTimeout 會在最後執行。
總結
本文主要講解了 javascript 的事件迴圈機制,程式碼自上而下執行過程中,是存在非同步執行的過程的,但在當前所有同步任務的執行依舊是自上而下的。另外,本文主要講解了
Promise
的主要用法,詳情可以參照 es6.ruanyifeng.com/#docs/promi…
猜歡迎大家在留言區探討更多的 Promise 使用~
喜歡的點個讚唄~
猜你喜歡
ES6 箭頭函式 www.jianshu.com/p/24d488844…
ES6 生成器 generator www.jianshu.com/p/91673eab0…