JavaScript的非同步處理
Javascript語言的執行環境是"單執行緒"(single thread,就是指一次只能完成一件任務。如果有多個任務,就必須排隊,前面一個任務完成,再執行後面一個任務,以此類推)。
為了解決這個問題,Javascript語言將任務的執行模式分成兩種:同步(Synchronous)和非同步(Asynchronous)。
“同步模式" 就是上一段的模式,後一個任務等待前一個任務結束,然後再執行,程式的執行順序與任務的排列順序是一致的、同步的;"非同步模式"則完全不同,每一個任務有一個或多個回撥函式(callback),前一個任務結束後,不是執行後一個任務,而是執行回撥函式,後一個任務則是不等前一個任務結束就執行,所以程式的執行順序與任務的排列順序是不一致的、非同步的。
“非同步模式" 非常重要。在瀏覽器端,耗時很長的操作都應該非同步執行,避免瀏覽器失去響應,最好的例子就是Ajax操作。在伺服器端,"非同步模式"甚至是唯一的模式,因為執行環境是單執行緒的,如果允許同步執行所有http請求,伺服器效能會急劇下降,很快就會失去響應。
回撥
回撥是 JS 中最原始,也是最古老的非同步通知機制。
function asyncFn(callback) { // 利用setTimeout模擬非同步 setTimeout(function () { console.log('執行完畢'); callback(); // 發通知 }, 2000); } asyncFn(function () { console.log('我會在2s後輸出'); });
事件監聽
任務的執行不取決程式碼的順序,而取決於某一個事件是否發生。
監聽函式有:on,bind,listen,addEventListener,observe
還是以f1和f2為例。首先,為f1繫結一個事件(採用jquery寫法)。
f1.on('done',f2);
上面程式碼意思是,當f1發生done事件,就執行f2。
釋出訂閱
promise
(1)promise物件是commonJS工作組提出的一種規範,一種模式,目的是為了非同步程式設計提供統一介面。
(2)promise是一種模式,promise可以幫忙管理非同步方式返回的程式碼。他講程式碼進行封裝並新增一個類似於事件處理的管理層。我們可以使用promise來註冊程式碼,這些程式碼會在在promise成功或者失敗後執行。
(3)promise完成之後,對應的程式碼也會執行。我們可以註冊任意數量的函式再成功或者失敗後執行,也可以在任何時候註冊事件處理程式。
(4)promise有兩種狀態:1、等待(pending);2、完成(settled)。
promise會一直處於等待狀態,直到它所包裝的非同步呼叫返回/超時/結束。
(5)這時候promise狀態變成完成。完成狀態分成兩類:1、解決(resolved);2、拒絕(rejected)。
(6)promise解決(resolved):意味著順利結束。promise拒絕(rejected)意味著沒有順利結束。
//promise
var p=new Promise(function(resolved))
//在這裡進行處理。也許可以使用ajax
setTimeout(function(){
var result=10*5;
if(result===50){
resolve(50);
}else{
reject(new Error('Bad Math'));
}
},1000);
});
p.then(function(result){
console.log('Resolve with a values of %d',result);
});
p.catch(function(){
console.error('Something went wrong');
});
(1)程式碼的 關鍵在於setTimeout()的呼叫。
(2)重要的是,他呼叫了函式resolve()和reject()。resolve()函式告訴promise使用者promise已解決;reject()函式告訴promise使用者promise未能順利完成。
(3)另外還有一些使用了promise程式碼。注意then和catch用法,可以將他們想象成onsucess和onfailure事件的處理程式。
(4)巧妙地方是,我們將promise處理與狀態分離。也就是說,我們可以呼叫p.then(或者p.catch)多少次都可以,不管promise是什麼狀態。
(5)promise是ECMAscript 6管理非同步程式碼的標準方式,javascript庫使用promise管理ajax,動畫,和其他典型的非同步互動。
簡單的說,它的思想是:每一個非同步任務返回一個promise物件,該物件有一個then方法,允許指定回撥函式。
f1.then(f2);
Promise.all
//使用場景,同時從不同地方請求多條資料時
Promise.all([
$.ajax({
url:"1.txt"
}),
$.ajax({
url:"2.txt"
})
]).then(
(data)=>{
console.log(data)
}
)
generator
生成器函式 可以暫停
//1.生成器函式 優點 先等待非同步完成 再執行下面的程式碼
//yield 後面的值給了下一個next()
function *show(){
alert(1);
let data= yield new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(100);
}, 5000);
})
console.log(data);
alert(2);
}
//2.呼叫next() 完整
//3.變數去接 生成器函式
//生成器函式呼叫必須配合 .next
let s=show();
let p=s.next();
console.log(p);
console.log(p.value);
let m= p.value.then((data)=>{
s.next(data)
console.log(data);
})
// p.value.then((data)=>{
// s.next(data);
// })
//引數 變數.next(引數) =>let 變數 =>yield
//返回 yield()===> 變數.next()
async/await
當前 JavaScript 中,處理非同步的最佳方案。
async函式返回一個 Promise 物件,可以使用then方法添加回調函式。當函式執行的時候,一旦遇到await就會先返回,等到非同步操作完成,再接著執行函式體內後面的語句。
async函式內部return語句返回的值,會成為then方法回撥函式的引數。
async function show() {
alert(1);
let data = await new Promise((resolve,reject)=>{
//網路請求時間來決定的
setTimeout(() => {
resolve(100)
}, 3000);
})
console.log(data)
let Data = await new Promise((resolve,reject)=>{
//網路請求時間來決定的
setTimeout(() => {
resolve({
name:"heson",
age:12
})
}, 3000);
})
console.log(Data)
alert(2);
}
show();