---
tags: JAVASCRIPT
---
【js筆記】非同步 & Promise
===
### Ajax
#### method
- get 取得
- post 新增(安全性較get高)
- put 更新
- delete 刪除
### 非同步常見問題
- 回呼問題
- 寫法不一致,多層巢狀,波動拳問題
- 無法同時執行(jQuery有並行寫法,但不直覺)
```javascript
const url = "https://randomuser.me/api/";
$.ajax({
url: url
}).done(function(res) {
const seed = res.info.seed;
console.log(seed, res)
$.ajax({
url: `${url}?seed=${seed}`
}).done(function(res2) {
console.log(res2)
});
});
```
# Promise
Promise 是一個表示非同步運算的最終完成或失敗的物件
```javascript
promise.then(successCallback, failureCallback);
```
- 寫法一致
- 都用 then
- then,return axios.get(...),減少多層巢狀
- all,同時發出請求,確保都完成時才執行結果
```javascript
Promise.all([axios.get(url), axios.get(url)])
.then(([res1, res2])=>{
console.log(res1, res2);
});
```
## 創立自己的promise
```javascript
function promiseFn(num) {
return new Promise((resolve, reject)=>{
setTimeout(() => {
if(num) {
resolve(`成功 ${num}`);
} else {
reject('失敗');
}
}, 10);
});
}
promiseFn(1)
.then( res => {
console.log(res);
return promiseFn(0);
})
.then( res => {
console.log(res);
return promiseFn(3);
})
.then(res => {
console.log(res)
})
.catch(res=>{
console.log('catch', res);
return promiseFn(4)
})
.then(res => {
console.log(res)
})
console.log('程式碼end');
```
## 可直接使用then來接收"成功"及"失敗"
```javascript
promiseFn(0)
.then( (res)=> {
console.log('success', res);
}, (res) => {
console.log('fail', res);
})
```
## Promise 的 chain, 串接
有個常見的需求是依序呼叫兩個以上的非同步函數,我們稱之為建立 Promise 鏈。
```javascript
promiseFn(1)
.then( res => {
console.log(res);
return promiseFn(2);
})
.then( res => {
console.log(res);
})
```
## Promise常見方法
#### all
- 回傳array
- 其中一個失敗者失數
- all 很常用:對遠端作出請求,發出多個api,當api都做完才進行下個步驟
```javascript
Promise.all([
promiseFn(1, 500),
promiseFn(2, 1000),
promiseFn(3, 3000),
])
.then((res)=>{
console.log(res); //傳回array
console.log(res[0], res[1], res[2])
})
.catch((rej)=>{
console.log(rej)
})
```
#### race
- 回傳第一個執行完的結果
- 非第一個執行完的有失敗,就不會失數
```javascript
Promise.race([
promiseFn(0, 500),
promiseFn(2, 20),
promiseFn(3, 3000),
])
.then((res)=>{
console.log(res); //傳回第一個完成結果
})
.catch((rej)=>{
console.log(rej) // 第一個完成的出錯才會進到這裡
});
```
## promise & ajax結合
### XMLHttpRequest
[XMR說明](https://developer.mozilla.org/zh-TW/docs/Web/API/XMLHttpRequest)
- 藉由 XMLHttpRequest(XHR)物件的方式來存取伺服器端的資料,可以讓你直接經由指定的 URL 擷取資料卻不用刷新整個網頁。
- 不好管理
```javascript
const url = "https://jsonplaceholder.typicode.com/todos/1";
var req = new XMLHttpRequest();
//定義方法
req.open('GET', url);
req.onload = function() {
if(req.status = 200) {
console.log(req.response);
} else {
// 失敗的話
}
};
req.send();
```
- 透過promise來實行
```javascript
function get(url) {
return new Promise((resolve, reject) => {
var req = new XMLHttpRequest();
//定義方法
req.open('GET', url);
req.onload = function() {
if(req.status = 200) {
resolve(req.response);
} else {
// 失敗的話
reject(req)
}
};
req.send();
});
}
get(url)
.then(res => {
console.log('get ', res);
return get(url);
})
.then(res => {
console.log('get2 ', res);
})
.catch(err => {
console.log(err)
})
```
# Axios
- 依賴 ES6 Promise,若不支援請使用 Polyfill
- 支援 Promise API
- 可取消請求 (Promise 無法)
- 自動轉換 JSON
```javascript
axios.get(url)
.then((res)=>{
console.log(1, res);
const seed = res.data.info.seed;
return axios.get(`${url}?seed=${seed}`)
})
.then((res)=>{
// 接收上一個then的return值
console.log(2, res);
})
```