promise,與async函式
一、Promise
1.1回顧回撥函式:
1).概念:
一個函式在另一個函式呼叫(一個函式傳遞另一個函式做引數使用)
2).非同步和同步:
在js,在主執行緒上面,先執行同步任務,再執行非同步任務,等主執行緒上的同步任務全部完成之後,回到非同步佇列進行查詢,將非同步佇列裡面的任務放到執行棧中,繼續遵循規則;
同步:排隊執行;
非同步:不會阻塞後面程式碼執行;
1.2 promise
1)概念: 解決非同步程式設計的方法
2)語法: 需要new 例項化;resolve返回的是成功狀態值;reject返回的是失敗狀態值;
接收失敗狀態的區別:
1. catch直接捕獲reject返回的失敗狀態值;
2.then裡面有第二個引數err,捕獲就是失敗狀態值;
區別:使用catch,不僅可以接收reject返回的失敗狀態值,也可以捕獲在成功狀態時,處理業務邏輯時報的錯;then裡面的第二個回撥函式來接收;只能捕獲reject返回的失敗狀態的值
3)特點:
1. 三種狀態:進行時,已成功,已失敗
2. 兩種狀態轉換:進行時=》已成功;進行時=》已失敗
4)promise一旦建立就會立即執行(同步任務);
呼叫resolve或reject執行非同步任務;狀態也會發生改變:由進行中=》已成功或者是已失敗;
console.log(1); let p1 = newPromise((resolve, reject) => { console.log('promise'); // 同步任務 進行中 resolve("success"); }); p1.then(res => { console.log(res) // 非同步任務 微任務 }); console.log(2); // 最終打印出的結果先後順序為 1, promise, 2, success
5)鏈式呼叫:從第二個then開始,拿的是上一個 then return之後的返回值;
案例1:
function fn(num) { return new Promise(resolve => { setTimeout(() => { resolve(num) }, 1000); }); }; console.log(fn()); fn(10).then(res => { console.log(res) return fn(++res) }).then(res => { console.log(res) return fn(++res) }).then(res => { console.log(res) });
6)解決回撥地獄:
ajax請求成功與失敗結果與promise本身的成功與失敗的狀態沒有必然的聯絡
function myAjax({ type = "get", url, data = {} }) { return new Promise((resolve, reject) => { $.ajax({ type, url, data, success: function(response) { resolve(response.result.data); } }) }); };
7)Promise.all 和 Promise.race
Promise.all() 做併發處理,等所有的請求有了返回值之後,同一返回,返回的是一個數組;
Promise.race() 獲取的是請求速度最快的值;(設定定請求時間,超過500ms的時候,提示使用者請求超時。)
let p1 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('123'); },5000); }); let p2 = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('456'); // reject('error'); },1000); }).catch(err=>{ console.log(err); }) ; Promise.all([p1,p2]).then(res=>{ console.log(res); // ["123", "456"] 等5s後才會打印出 }); Promise.race([p1,p2]).then(res=>{ console.log(res); // 456 });
錯誤捕獲兩種方法:
直接在all方法後面直接寫catch;只返回失敗狀態值,其他請求成功狀態的值,無法返回;
誰返回的失敗狀態,誰來處理;既可以接收本身自己的失敗狀態值,其他請求成功狀態的值,也不受影響
二、async函式:
1.Async 函式是Generator函式語法糖;
2.語法:
1)在function前面加async關鍵字;
箭頭函式async關鍵字放在形參的前面;
2)返回的是一個promise物件;
3)await 等待:
1.await後面的值,不會返回到函式的外部;
2.async函式內可以有多個await
3.await等待的是後面表示式的結果值;注意,如果是promise物件,預設情況下只返回成功狀態值;
4.await有阻塞後面程式碼執行作用,await後面的表示式有結果之後,下面的程式碼才可以執行;
5.async函式內部是同步任務;不影響主執行緒上任務的執行順序;
let p1 = new Promise(resolve => { setTimeout(() => { resolve("p1") }, 3000); }); console.log("fn start"); async function fn() { console.log(1); let a = await p1; console.log(a); console.log(2); }; console.log("fn end"); fn();
4)捕獲錯誤資訊:
- 直接使用catch
- Try...catch
- 優雅封裝方法:
let p1 = new Promise((resolve, reject) => { if (true) { resolve("success") } else { reject("失敗") }; }); // promise自己呼叫catch方法 // async function fn() { // let a = await p1.catch(err => { // console.log(err) // }); // console.log(a); // }; // fn(); // try...catch // async function fn() { // try { // let a = await p1; // console.log(a) // } catch (error) { // console.log(error) // }; // }; // fn(); // 優雅捕獲錯誤 function to(promise) { return promise.then(res => [null, res]).catch(err => [err,undefined]); }; async function fn() { let [err, data] = await to(p1); console.log(err, data); }; fn();
5)解決回撥地獄:
案例1:1秒列印一個1:
function fn2() { return new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }) } async function fn3() { let a = await fn2(); console.log(a); let b = await fn2(); console.log(b); let c = await fn2(); console.log(c); let d = await fn2(); console.log(d); } fn3();
案例2:ajax封裝
function myAjax({ type = "get", url, data = {} }) { return new Promise(resolve => { $.ajax({ type, url, data, dataType: "jsonp", success: function(response) { resolve(response); } }) }); };