進階 Javasctipt 概念 (6)

PY
6 min readApr 16, 2019

--

非同步原理解析

工作中最常使用到的莫過於 Ajax 了,Ajax 全名為非同步的 JavaScript 與 XML,當你發出 api 請求給後端 server,基於第一章提到的 call back queue,web api 會把這些請求放入 call back queue 等到最後再執行,但問題是當你要執行的 function 需要這些資料怎麼辦,讓我們來看看 JS 怎麼解決這讓人頭痛的問題

首先來讓我們複習一下第一章,重新再看一下 Call Stack

Promises

提到 Promises 前,得先提到回呼函式 call back function

getApi('xxx', function(){
getApi('xxx', function(){
getApi('xxx', function(){
})
})
})

當你要等待某隻 api 完成後,才能執行下一個 api ,我們把函式當成參數一層一層傳遞下去變成回呼函式, 這樣巢狀的函式既不美觀又不方便維護,常常演變為大家俗稱的回呼地獄

這時 Promise 出現了

Promise 解決了回呼地獄,promise 有三種狀態 resolve, reject, pending,分別代表完成、失敗、等待中

var promise = new Promise(function(resolve, reject) {// do something, possibly asyncif (/* everythings fine */) {resolve(result);} else {reject(err);}});
promise.then(function(result) {
// 拿到result了});

上面是個標準的 promise,resolve 代表你已經 fulfilled 完成動作,然後將 result 用 resolve 傳到下一個 .then 再接續下去 .then,形成鏈式調用

錯誤處理

錯誤處理的部分我們可以用 throw Error + catch 捕獲所有在 .then function 中的錯誤

promise.then(function(result) {}).then(result =>{
throw Error
}).catch(()=>console.log('error'))

Promise.all

你想讓某些 promise 都執行完後才執行動作可以用 Promise.all

var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});

Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
}).catch(()=> console.log('error'))

Promise.all 對你要執行的其他 promise 封裝成一個 Promise,打包起來後他會等 p1, p2, p3 都亮綠色後才執行裡面的動作,當一個亮紅燈就會立即返回,我們可以用在當不同的 ajax 不互相牽扯各自返回的資料時,能夠打包在一起執行

Async Await

async await 是 es6 專門給 promise 用的語法糖,他在 promise 外加上了 async await 的關鍵字,讓我們不需要使用鏈式語法就能讓 ajax 同步執行

async function fetchUsers(){
let users= await fetch('https://jsonplaceholder.typicode.com/users')
let data = await users.json()
console.log(data)
}

await 必須返回 promise 物件,所以你也可以在 users 後面 .then 返回抓到的資料,await 會等待動作執行完後才會繼續執行下一行,我們可以在 async 裡面做 try catch 錯誤處理

async function fetchUsers(){
try {
let users= await fetch('https://jsonplaceholder.typicode.com/users')
let data = await users.json()
console.log(data)
} catch(err) {
console.log('error ' + err)
}
}

Job Queue vs Call back Queue

Job Queue 稱為工作佇列,用於 Promise 中,他的優先層級大於 Call back Queue

//1
setTimeout(()=>{console.log('1', 'is the loneliest number')}, 0)
setTimeout(()=>{console.log('2', 'can be as bad as one')}, 10)//2Promise.resolve('hi').then((data)=> console.log('2', data))//3console.log('3','is a crowd')

順序是 3 -> 2 -> 1,我們可以有許多的 Job Queue ,但只能有一個 Call back Queue ,所以我們會先執行 Job Queue 後,再進入 Event Loop

Parellel, Sequencial, Race

1. parellel 平行

Promise.all 代表將所有 ajax 一起執行,等到完成後再一起返回結果,此時如果當有一人被 reject ,就會一起失敗

2. race

顧名思義就是來賽跑的,Promise.race 會返回第一個成功執行的 ajax

3. Sequence

Sequence 順序是最常見的,像是 async await 等前一個完成後再執行下一個

總結

還是要提一下 JS 是單執行緒非阻塞的語言,意指他不能併發,同時跑兩個動作,你只能靠著 Event loop、call back queue 讓程式等待執行,如果要讓非同步事件進行同步回調,那就可以用 Promise 讓程式進入 Job Queue

--

--