JS中的異步操做從最初的回調函數演進到Promise,再到Generator,都是逐步的改進,而async函數的出現彷彿看到了異步方案的終點,用同步的方式寫異步。ajax
原文連接promise
簡單解釋async函數就是Generator函數的語法糖。異步
Generator函數寫法async
let promise = function (val){ return new Promise(function (resolve, reject){ setTimeout(()=>{ console.log(val); resolve(val); },1000); }); }; let gen = function* (){ let p1 = yield promise('1'); let p2 = yield promise('2'); }; let genF = gen();
async函數寫法函數
let promise = function (val){ return new Promise(function (resolve, reject){ setTimeout(()=>{ console.log(val); resolve(val); },1000); }); }; let gen = async function (){ let p1 = await promise('1'); let p2 = await promise('2'); };
async函數是在Generator函數上進行的改進,語法上Generator函數的星號換成了async,yield換成了await。
而async也與Generator函數不一樣:spa
寄予async函數的指望是但願能夠幫助咱們解決異步操做問題,因此須要搞清楚async函數的返回值是什麼。code
async function asyncAwait() { return 'async await'; } let a = asyncAwait(); console.log(a);
結果輸出:對象
Promise {<resolved>: "async await"}
能夠看出async函數返回的是一個Promise對象,若是函數中return一個直接量,async函數會封裝成Promise對象返回,而若是沒有返回值時,async函數會返回undefinedrem
Promise {<resolved>: undefined}
在沒有結合await時,async函數會當即執行,返回一個Promise對象。字符串
await是個運算符,等待的結果是Promise對象或其餘值,好比:
function func1() { return 'async'; } async function func2() { return Promise.resolve('await'); } async function asyncAwait() { let f1 = await func1(); let f2 = await func2(); console.log(f1, f2); } asyncAwait()
結果輸出:
async await
await表達式的運算取決於等待的結果,若是它等到的不是一個Promise對象,那運算結果就是它等到的東西,
而若是它等到的是一個Promise對象,它會阻塞後面的代碼,等着Promise對象resolve,而後獲得resolve的值,做爲表達式的運算結果。
async函數調用會封裝在Promise中,這也是await須要在async函數中使用的緣由。
對於多個異步操做中,Promise的then能夠解決多層回調問題。
function ajax(t) { return new Promise(resolve => { setTimeout(() => resolve(t + 200), t); }); } function step1(t) { console.log(`step1 in ${t}ms`); return ajax(t); } function step2(t) { console.log(`step2 in ${t}ms`); return ajax(t); } function step3(t) { console.log(`step3 in ${t}ms`); return ajax(t); } function submit(){ console.time('submit'); step1(200) .then(time2 => step2(time2)) .then(time3 => step3(time3)) .then(result => { console.log(`result is ${result}ms`); console.timeEnd("submit"); }); } submit();
async函數實現:
function ajax(t) { return new Promise(resolve => { setTimeout(() => resolve(t + 200), t); }); } function step1(t) { console.log(`step1 in ${t}ms`); return ajax(t); } function step2(t) { console.log(`step2 in ${t}ms`); return ajax(t); } function step3(t) { console.log(`step3 in ${t}ms`); return ajax(t); } async function submit(){ console.time('submit'); const t1 = 200; const t2 = await step1(t1); const t3 = await step2(t2); const result = await step3(t3); console.log(`result is ${result}`); console.timeEnd('submit'); } submit();
結果輸出:
step1 in 200ms step2 in 400ms step3 in 600ms result is 800 submit: 1209.85107421875ms
而若是需求變動,每一步的參數都是以前步驟的結果後,async函數能夠寫成:
function ajax(t) { return new Promise(resolve => { setTimeout(() => resolve(t + 200), t); }); } function step1(t1) { console.log(`step1 in ${t1}ms`); return ajax(t1); } function step2(t1, t2) { console.log(`step2 in ${t1}ms,${t2}ms`); return ajax(t1 + t2); } function step3(t1, t2, t3) { console.log(`step3 in ${t1}ms,${t2}ms,${t3}ms`); return ajax(t1 + t2 + t3); } async function submit(){ console.time('submit'); const t1 = 200; const t2 = await step1(t1); const t3 = await step2(t1, t2); const result = await step3(t1, t2, t3); console.log(`result is ${result}`); console.timeEnd('submit'); } submit();
結果輸出:
step1 in 200ms step2 in 200ms,400ms step3 in 200ms,400ms,800ms result is 1600 submit: 2210.47998046875ms
async function asyncAwait() { try { await promise(); } catch (err) { console.log(err); } } // 另外一種寫法 async function asyncAwait() { await promise().catch(function (err){ console.log(err); }); }
async/await是ES7的重要特性之一,也是目前社區裏公認的優秀異步解決方案,當你深刻了解原理後會發現彷彿看到了異步回調隧道的盡頭亮光。