--- 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); }) ```