今天要學習的是 Async
與 Await
,是為了簡化 Promise
物件的操作流程而誕生。
來看看 MDN 怎麼描述:
async/await 函式的目的在於簡化同步操作 promise 的表現,以及對多個 Promise 物件執行某些操作。就像 Promise 類似於具結構性的回呼函式,同樣地,async/await 好比將 generator 與 promise 組合起來。
原本使用 Promise
物件時,我們會需要透過 then()
與 catch
取得 resolve
與 reject
的結果。 但 async
/await
的出現簡化了透過then()
與 catch
取得值的過程
來看一個測試例子:
//定義一組 promise
const runTime = (time, person) => {
return new Promise((reslove, reject) => {
setTimeout(() => {
reslove(`${person}`)
}, time);
});
}
// 透過 then() 取得 resolve 的結果
const result = runTime(3000, 'Bill').then(res => console.log(res));
console.log(result);
上述預期可以得到的值為 Bill
,應該沒有問題。
再來看看透過 async
/await
改寫一下上面的例子:
function runTime(time, person) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${person}`);
}, time);
});
}
async function getPerson() {
const result = await runTime(3000, 'Bill');
console.log(result);
}
getPerson();
在前面有提到,async
/await
的出現簡化了透過then()
與 catch
取得值的過程。
所以預期可以得到的值為 Bill
。
先記住這個差別,接下來要提提 async
/await
為什麼能夠這麼做。
以下是 MDN的語法:
async function name([param[, param[, ... param]]]) {
statements
}
首先是 async
關鍵字,在函式前寫上 async
, 表示該函式為一個非同步函式,並且會得到一個 Promise
物件的回應結果
let sayHi = async () => 'Hello!';
sayHi() // 預期可以得到一個 Promise {<resolved>: "Hello!"} 的回應
然後我們就可以透過 then()
的方式取得最後結果
let sayHi = async () => 'Hello!';
sayHi().then(res => console.log(res))
再來是 await
關鍵字,當這個函式被呼叫時,透過撰寫在 statements 裡面的 await
接收一個 Promise
物件,並且會等到解析完當前Promise
物件的狀態(resolve
或 reject
)後才會繼續往下執行。
let sayHi = async () => await Promise.resolve('Hello');
sayHi()
這邊要注意的是 await
會中斷 async
函式的執行直到解析完Promise
物件的狀態後才往下執行。
所以今天如果有多個 非同步函式使用 async
/await
的話,秒數則為加總後的時間。
來看看這個測試例子:
function runTime(time, person) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${person}`);
}, time);
});
}
async function getTimes() {
console.time();
const result = await runTime(1000, 'Bill');
const result2 = await runTime(3000, 'Jack');
console.timeEnd();
}
getTimes();
透過設定 console.time()
、 console.timeEnd()
計算使用 async
/await
的非同步函式的總執行時間。會發現約4000毫秒(約4秒),因為 async
/await
是一個執行完成後再執行下一個的(串行執行)。
那問題來了,如果要能並行執行呢?
還記得前一篇提到的 Promise.all
吧?
這裡就要透過 async
/await
搭配 Promise.all
,來看看測試例子:
function runTime(time, person) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${person}`);
}, time);
});
}
async function getTimes() {
console.time();
const result = await Promise.all([runTime(1000, 'Bill'),runTime(3000, 'Jack')]);
console.timeEnd();
}
getTimes();
從得到的結果可以發現,使用 Promise.all
可以並行執行,進而縮短執行時間。
async
/await
搭配 fetch
介接高雄市資料開放平臺的 open data最後以介接 open data的實作結束這一回合~
<!-- css part -->
<style>
body {
background: #f0d0d0;
}
h1 {
text-align: center;
font-weight: bold;
font-size: 48px;
}
.charge-list {
display: flex;
list-style: none;
flex-wrap: wrap;
}
.charge-list li {
box-sizing: border-box;
flex: 0 1 24%;
padding: 10px;
margin: 0 1% 2% 0;
border-radius: 10px;
transition: all .4s;
}
.charge-list li:hover {
margin-top: -1%;
}
.charge-list li:nth-child(n) {
background: #aaaadd;
}
.charge-list li:nth-child(2n) {
background: #ddddaa;
}
.charge-list li:nth-child(3n) {
background: #dad;
}
.charge-list li:nth-child(3n+1) {
background: #aaf;
}
</style>
<!-- html -->
<ul class="charge-list"></ul>
async
/await
搭配 fetch
介接open datafetchData = endPoint => fetch(endPoint).then(res => res.json());
(async function getData()
const endPoint = 'https://data.kcg.gov.tw/dataset/a98754a3-3446-4c9a-abfc-58dc49f2158c/resource/48d4dfc4-a4b2-44a5-bdec-70f9558cd25d/download/yopendata1070622opendatajson-1070622.json';
try {
let chargeStation = await fetchData(endPoint);
createDomElement(chargeStation);
}
catch(e){
console.log(e);
}
})();
function createDomElement(chargeStation) {
const domElements = chargeStation.map(place => {
return `
<li>
<p class="location">位置: ${ place.Location }</p>
<p class="address">地址:${ place.Address }</p>
</li>
`;
}).join("");
const chargeList = document.querySelector('.charge-list');
chargeList.innerHTML = domElements;
}
今天就先到這裡囉~
明天見~