owned this note
owned this note
Published
Linked with GitHub
---
title: javascript 6.14 AJAX
tags: javascript, 5x
---
6.14 0327 javascript AJAX
===
# Asynchronous JavaScript and XML
非同步的JavaScript and XML
AJAX特性:
* 使用 javascript 為主要程式語言
* 使用 XML 做為資料交換的格式
* 使用 DocumentObjectModel 的方式編修HTML
* 使用 XMLHttpRequest 物件來傳輸與接收資料
* 使用 XHTML 與 CSS 以呈現資料
Ref: https://ithelp.ithome.com.tw/articles/10074729
# 同步與非同步
同步: 打電話。需要等對方回應才能進行下一個步驟
非同步:傳訊息。不需要等對方回應,可以先去做其他的事情
## 同步案例:乒乓球
1. 打乒乓球必須一來一回
```javascript
function ping() {
console.log('ping!');
}
function pong() {
console.log('pong!');
}
function play() {
console.log('Go!');
ping();
pong();
console.log('Game Set!');
}
play();
```
console
```javascript
"Go!"
"ping!"
"pong!"
"Game Set!" //按照順序
```
2. 加入延遲時間的情況,結果並沒有按照順序
```javascript
function ping() {
console.log('ping!');
setTimeout(() => {
console.log('殺球!!!');
}, 3000)
//3000 mini secs = 3 secs
}
function pong() {
console.log('pong!');
}
function play() {
console.log('Go!');
ping();
pong();
console.log('Game Set!');
}
play();
```
console
```javascript
"Go!"
"ping!"
"pong!"
"Game Set!"
"殺球!!!" // 殺球在game set 之後出現
```
# AJAX優點
1. 非同步:在不更新整個頁面的情況去修改部分的資料
2. 常見用途:API
# 1. 非同步語法: `promise(resolve, reject)`
`promise()`有兩個參數: 成功`resolve`, 失敗`reject`
1. `resolve`: 成功才做下一步`.then()`,失敗則不做
```javascript
let killer = new Promise((resolve, reject) => {
resolve('十萬福特');
});
killer.then( skill => { //上一步成功,才會接到這一步
console.log(skill);
})
```
console
```javascript
"十萬福特"
```
2. `reject`: 失敗時`.then()`沒反應
```javascript
let killer = new Promise((resolve, reject) => {
reject('十萬福特');
});
killer.then( skill => { //上一步成功,才會接到這一步
console.log(skill);
})
```
console: 沒有印出資料
```javascript
```
3. 失敗時,丟參數進去`.catch(error => )`
```javascript
let killer = new Promise((resolve, reject) => {
reject('十萬福特');
});
killer.then( skill => { //上一步成功,才會接到這一步
console.log(skill);
}).catch( error => {
console.log('error = ' + error)} )
```
console
```javascript
"error = 十萬福特"
```
## `setTimeout()`用途:等到事件完成之後再呈現資料
4. 加入延遲時間的情況
```javascript
let killer = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('十萬福特');
}, 3000)
});
killer.then( skill => { //上一步成功,才會接到這一步
console.log(skill);
}).catch(error => {
console.log('error = ' + error)
})
```
console: 三秒之後印出十萬伏特
```javascript
"十萬福特"
```
# 練習: 釋放大絕招遊戲
三秒內點五次按鈕,放出大絕招 **元氣玉**
完成品連結 https://codepen.io/tingtinghsu/full/qwbrMr
Step 1. jQuery起手式
```javascript
$(document).ready(() => {
});
```
Step 2. 抓`hitbutton`
```javascript
$(document).ready(() => {
$('#hitButton').click( evt => {
})
});
```
Step 3. 點擊計數
```javascript
let chi = 0;
$(document).ready(() => {
$('#hitButton').click( evt => {
evt.preventDefault();
chi += 1;
$('#hitButton').text(`集氣 (${chi} 次) `);
})
});
```
Step 4. 設定 `promise` 函數: 成功resolve, 失敗reject
```javascript
let 大絕招 = new Promise((resolve, reject) => {
setTimeout(() => {
if( chi >= 5 ) {
resolve('元氣玉');
} else {
reject('元氣玉');
}
}, 3000)
})
```
Step5. 成功和失敗時所呈現的html
```javascript
大絕招.then(招式 => {
$('#result').html(`使用絕招:${招式}`)
}).catch(err => {
$('#result').html(`${err}無法使用!`)
})
```
Step5. 整理成一行
```javascript
大絕招
.then(招式 => $('#result').html(`使用絕招:${招式}`))
.catch(err => $('#result').html(`${err}無法使用!`))
```
小結
```javascript
// javascript程式碼寫在這裡
let chi = 0;
$(document).ready(() => {
$('#hitButton').click( evt => {
evt.preventDefault();
chi += 1;
$('#hitButton').text(`集氣 (${chi} 次) `);
})
});
let 大絕招 = new Promise((resolve, reject) => {
setTimeout(() => {
if( chi >= 5 ) {
resolve('元氣玉');
} else {
reject('元氣玉');
}
}, 3000)
});
大絕招.then(招式 => {
$('#result').html(`使用絕招:${招式}`)
}).catch(err => {
$('#result').html(`${err}無法使用!`)
})
```
# 2. 什麼是API
Application Programming Interface
應用程式介面
提供開發人員一些預先定義好的函式庫,可以快速使用其功能而不必了解實際運作。
## 常見的Web API回應格式
JSON / XML / CSV
## JSON
JavaScript Object Notation
JS物件表示法
JSON資料格式的表示
https://jsoneditoronline.org/
物件(object)用大括號 { }
陣列(array)用中括號 [ ]
範例:
```json
{
"name": "Ting",
"lastname": "Ting",
"report": [
{
"subject": "Math",
"score": 80
},
{
"subject": "English",
"score": 90
}
]
}
```
## XML
Extensible-Markup Language
可延伸標記語言
有含意的標籤取名
```xml
<news>
<to>日本</to>
<from>台灣</from>
<heading>鈴木一朗要退休了!</heading>
<body>不.....................</body>
</news>
```
## CSV
Comma-Separated Values
逗號分隔值
```xml
"1997","Ford","E350"
```
# 練習: 製作API抓取網路資料
農產品價格
完成品:https://codepen.io/tingtinghsu/full/QPyerz
Step 1. jQuery起手式
```javascript
//希望DOM元素載完再做其他的事情
$().ready(() => {
});
```
## 抓網路資料 `fetch()`
抓資料網址http://data.coa.gov.tw/Service/OpenData/FromM/FarmTransData.aspx
Step 2. `fetch()`
回傳一個Promise(). then()可以接著處理抓回來的資料
```javascript
//DOM元素載完後再做其他的事情
$().ready(() => {
fetch('http://data.coa.gov.tw/Service/OpenData/FromM/FarmTransData.aspx').then( response => { console.log(response)})
});
```
console 出現錯誤訊息:
```javascript
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at http://data.coa.gov.tw/Service/OpenData/FromM/FarmTransData.aspx.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
```
## CORS的含義
Cross-Origin Resource Sharing
跨網域資料分享
若是抓取的網站沒有開CORS,可以
1. 使用CORS Proxy(可能不太穩定)
2. 用後端程式抓
改成另外的網址
```javascript
//DOM元素載完後再做其他的事情
$().ready(() => {
fetch('https://ubin.io/data/vegetables?item=香蕉').then( response => { console.log(response)})
});
```
console
```javascript
Response { type: "cors", url: "https://ubin.io/data/vegetables?item=%E9%A6%99%E8%95%89", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, body: ReadableStream, bodyUsed: false }
```
Step 3. 把抓取菜價的功能提出成為`function getVegetablePrice()`
可傳不同的蔬菜參數進去
```javascript
$().ready(() => {
getVegetable('香蕉');
});
function getVegetable(item) {
fetch(`https://ubin.io/data/vegetables?item=${item}`).then( response => {
console.log(response)
})
}
```
console
```javascript
Response { type: "cors", url: "https://ubin.io/data/vegetables?item=%E9%A6%99%E8%95%89", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, body: ReadableStream, bodyUsed: false }
```
Step 4. 解析轉成json格式,再回傳一個promise
```javascript
function getVegetable(item) {
fetch(`https://ubin.io/data/vegetables?item=${item}`)
.then( response => {
// 解析轉成json格式
return response.json()
// 再回傳一個promise
})
.then(data => {console.log(data)})
}
```
console
```bash=
item: "香蕉"
prices: (9) […]
0: Object { market: "台北二", price: 23.8 }
1: Object { market: "台北一", price: 22.4 }
2: Object { market: "板橋區", price: 24.6 }
3: Object { market: "三重區", price: 24.7 }
4: Object { market: "宜蘭市", price: 22 }
5: Object { market: "台中市", price: 21.2 }
6: Object { market: "豐原區", price: 19.38 }
7: Object { market: "高雄市", price: 25 }
8: Object { market: "鳳山區", price: 23 }
length: 9
```
## 將抓取的資料做成圖表
### installation
Chart.js:https://cdnjs.com/libraries/Chart.js
將js檔案另存新檔,放入資料夾。
### usage
https://www.chartjs.org/docs/latest/getting-started/usage.html
html
```htmlmixed
<head>
<script src="scripts/Chart.min.js"></script>
</head>
<body>
<canvas id="myChart" width="400" height="400"></canvas>
<script src="scripts/script.js"></script>
</body>
```
javascript
```javascript=
function getVegetable(item) {
fetch(`https://ubin.io/data/vegetables?item=${item}`)
.then( response => {
// 解析轉成json格式
return response.json()
// 再回傳一個promise
})
.then(data => { renderChart(data);}) //畫圖
}
```
Step 5. renderchart抓取蔬果資料(變數: market/price)
ES6的 `.map()`:
針對某個陣列的每個元素做某件事情,再重新搜集成一個陣列
```javascript=
function renderChart(data) {
let markets = data["prices"].map(p => {
return p.market
//等於 return price["market"]
})
//測試 console.log(markets);
let prices = data["prices"].map(p => {
return p["price"]
})
// 測試 console.log(prices);
```
整理更簡潔的程式碼
```javascript
let markets = data["prices"].map(p => p.market)
let prices = data["prices"].map(p => p.price)
```
最後,把抓好的資料填進去圖表!
```javascript
let title = `${data.item}價格`;
var ctx = $('#myChart');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: markets, //各地市場
datasets: [{
label: title, // 標題
data: prices, // 價格
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(155, 199, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
```
# 附錄
JSON Viewer(Chrome 外掛):https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh?hl=zh-TW
Chart.js:https://www.chartjs.org/
政府資料交換平台:https://data.gov.tw/
農產品交易行情(官方版):https://data.gov.tw/dataset/8066
農產品交易行情(特製版):https://ubin.io/data/vegetables?item=香蕉