async await
我們直接進入主題!!!
1.async和await是什么?
async:
是ES7語法,用於聲明一個function是異步函數。
await:
等待一個異步方法完成。
ps:await只能出現在async函數中,不然會報錯,如示例1-1;
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
Await只在異步函數和頂級模塊體中有效.
1 /*示例 1-1*/ 2 let fun = function (){ 3 console.log('錯誤示例'); 4 } 5 await fun(); 6 7 let fun1 = function(){ 8 console.log('正確示例'); 9 } 10 let fun =async function (){ 11 await fun1(); 12 } 13 fun();
2.async到底干了什么? (一): 我們先看一下async聲明的函數,返回值到底是個什么。 ps:如示例2-1; 可以看到返回的其實就是一個promise對象。Promise {<fulfilled>: "async"} 所以,async直接返回一個promise對象。如果在函數中直接return一個直接量,async會通過promise.resolve()封裝成promise對象。 ps:Promise.resolve(e)可以看作是 new Promise(resolve => resplve(e))的簡寫,可以快速將字面量對象或其他對象分裝成promise實例。 (二): 使用async不用await可以處理返回值嗎? ps:如示例2-2-1; 如示例2-2-2,async聲明的函數是一個promise對象,所以我們當然可以用then()鏈去處理。 (三): 到這里就會產生一個疑問,既然async返回是一個promise對象,並且promise的特點就是無等待,在沒有await的情況下會立即執行,不會阻塞后面的語句,和普通的promise並無二致, 我們為什么要用async和await呢? 我們看示例2-3-1,模擬了一個異步操作,因為promise並不會造成阻塞,所以打印2輸出為null,打印1會在一秒以后輸出111, 想一個問題如果我們有的代碼是基於異步完成之后的結果,要怎么處理?對,我們可以在then()函數中寫,如果有多個promise並且相互依賴呢?
1 /*示例2-1*/ 2 3 let fun = async function(){ 4 return 'async'; 5 } 6 console.log(fun());//Promise {<fulfilled>: "async"} 7 8 /*示例2-2-1*/ 9 fun().then(e=>{ 10 console.log(e);//async 11 }) 12 13 /*示例2-3-1*/ 14 var param = null; 15 16 let fun = () => { 17 return new Promise(resolve => { 18 setTimeout(() => resolve(function(){ 19 param = '111'; 20 }), 1000); 21 }); 22 } 23 24 fun().then(v => { 25 v(); 26 console.log(param,'1'); 27 }); 28 console.log(param,'2');
3.await到底在等什么? (一): 官方介紹,await等待的是一個promise對象或者是其它值。 實際await等待的是一個返回值,所以await后邊可以接普通函數,或者是直接量。 ps:如示例3-1-1。 (二): await等到了要等的東西,然后呢? await是一個運算符,用於組成表達式,await表達式的運算結果取決於等到的東西。 如果await等到的不是一個promise對象,那await運算結果就是等到的東西。 如果await等到的是一個promise對象,那會阻塞后面的代碼,等着promise對象resolve,然后得到resolve的值,最為await運算結果。 注意: 阻塞,只是async把所有的阻塞都封裝在一個promise對象中異步執行,這也是await必須使用在async函數中的原因。 ps:如示例3-2-1。 示例會先執行打印3 輸出null,然后一秒以后異步結束執行1,2。
1 /*示例3-1-1*/ 2 let fun = function () { 3 return "fun"; 4 } 5 6 let asyncFun = async function () { 7 return Promise.resolve("asyncFun"); 8 } 9 10 async function test() { 11 const v1 = await fun(); 12 const v2 = await asyncFun(); 13 console.log(v1, v2); 14 } 15 16 test(); 17 /*示例3-2-1*/ 18 var param = null; 19 20 let fun = () => { 21 return new Promise(resolve => { 22 setTimeout(() => resolve(function () { 23 param = '111'; 24 }), 1000); 25 }); 26 } 27 28 let awaitFun = async function () { 29 await fun().then(v => { 30 v(); 31 console.log(param, '1'); 32 }); 33 console.log(param, '2'); 34 } 35 awaitFun(); 36 console.log(param, '3');
4.目前看來使用Promise和async,await好像並沒有什么區別? (一): 我們簡單做一個比較。 不用async/await: ps:示例4-1-1。 使用async/await: ps:示例4-1-2。 好,我們發現好像並沒有什么區別?so,優勢到底在哪里? (二): async/await優勢: 其實單一的promise並不能發現async/await優勢,但是如果處理多個優勢就出來了。 說白了async/await好像就是用來優化promise。 現在,我們假設一個業務,分成多步,且每一步都依賴於上一步的結果。 ps:示例4-2-1。 有沒有發現什么??? 在看一個,把業務要求改一下,仍然是三個步驟,但每一個步驟都需要之前每個步驟的結果。 ps:示例4-2-2。 哇,是不是很神奇!!!
1 /*示例4-1-1*/ 2 let fun = function () { 3 return new Promise(resolve => { 4 setTimeout(() => resolve("not async/await!!!"), 1000); 5 }); 6 } 7 8 fun().then(v => { 9 console.log("async", v); 10 }); 11 /*示例4-1-2*/ 12 let fun = function () { 13 return new Promise(resolve => { 14 setTimeout(() => resolve("is async/await!!!"), 1000); 15 }); 16 } 17 18 async function test() { 19 const v = await fun(); 20 console.log(v); 21 } 22 23 test(); 24 25 /*示例4-2-1*/ 26 /** 27 * 傳入參數 n,表示這個函數執行的時間(毫秒) 28 * 執行的結果是 n + 200,這個值將用於下一步驟 29 */ 30 function getTime(n) { 31 return new Promise(resolve => { 32 setTimeout(() => resolve(n + 200), n); 33 }); 34 } 35 36 function step1(n) { 37 console.log(`step1 with ${n}`); 38 return getTime(n); 39 } 40 41 function step2(n) { 42 console.log(`step2 with ${n}`); 43 return getTime(n); 44 } 45 46 function step3(n) { 47 console.log(`step3 with ${n}`); 48 return getTime(n); 49 } 50 /*promise實現*/ 51 function doIt() { 52 console.time("doIt"); 53 const time1 = 300; 54 step1(time1) 55 .then(time2 => step2(time2)) 56 .then(time3 => step3(time3)) 57 .then(result => { 58 console.log(`result is ${result}`); 59 console.timeEnd("doIt"); 60 }); 61 } 62 63 doIt(); 64 /*async/await實現*/ 65 async function doIt() { 66 console.time("doIt"); 67 const time1 = 300; 68 const time2 = await step1(time1); 69 const time3 = await step2(time2); 70 const result = await step3(time3); 71 console.log(`result is ${result}`); 72 console.timeEnd("doIt"); 73 } 74 75 doIt(); 76 77 /*4-2-2*/ 78 function step1(n) { 79 console.log(`step1 with ${n}`); 80 return getTime(n); 81 } 82 83 function step2(m, n) { 84 console.log(`step2 with ${m} and ${n}`); 85 return getTime(m + n); 86 } 87 88 function step3(k, m, n) { 89 console.log(`step3 with ${k}, ${m} and ${n}`); 90 return getTime(k + m + n); 91 } 92 /*async/await實現*/ 93 async function doIt() { 94 console.time("doIt"); 95 const time1 = 300; 96 const time2 = await step1(time1); 97 const time3 = await step2(time1, time2); 98 const result = await step3(time1, time2, time3); 99 console.log(`result is ${result}`); 100 console.timeEnd("doIt"); 101 } 102 103 doIt(); 104 105 /*promise實現*/ 106 function doIt() { 107 console.time("doIt"); 108 const time1 = 300; 109 step1(time1) 110 .then(time2 => { 111 return step2(time1, time2) 112 .then(time3 => [time1, time2, time3]); 113 }) 114 .then(times => { 115 const [time1, time2, time3] = times; 116 return step3(time1, time2, time3); 117 }) 118 .then(result => { 119 console.log(`result is ${result}`); 120 console.timeEnd("doIt"); 121 }); 122 } 123 124 doIt();
5.總結 個人理解async/await是用來解決同步異步,更重要的是優化了promise。
ok,到此結束,后續會把實際應用場景更新進來,歡迎指出毛病哦!
6.補充:
處理錯誤邏輯
ps:示例6-1-1。
(一): try/catch/finally
如果try塊中的任何代碼發生了錯誤,就會立即退出代碼執行過程,然后接着執行catch塊,此時,catch塊會接收到一個包含錯誤信息的對象。
finally子句一經使用,其代碼無論如何都會執行。
只要代碼中包含finally子句,則無論try或catch語句塊中包含什么樣的代碼——甚至return語句,都不會阻止finally子句的執行。
執行順序try->catch->finally。
(二):JavaScript throw 語句:
Throw拋出一個錯誤。
創建自定義錯誤。
可拋出字符串,數字,邏輯值或對象。
!!!!!拋出錯誤javascript會停止往下執行。
ps: throw “ too bing”
throw 500
throw new Error(‘’這是一個錯誤!!!);
(三):函數定義方式
(1):函數聲明
function fun (a,b){
return a*b;
}
fun(1,2);
不會立即執行。
(2):函數表達式
let a = function(a,b){
return a*b;
}
a(1,2);
等同於匿名函數通過變量名調用。
(3):Function()構造函數
let fun = new Function('a','b','return a*b');
fun(1,2);
(4):函數提升
提升(Hoisting)是 JavaScript 默認將當前作用域提升到前面去的的行為。
提升(Hoisting)應用在變量的聲明與函數的聲明。
ps:示例6-3-4
(5):函數執行順序
ps:示例6-3-5
(6):作用域
ps:示例6-3-6
1 let fun = async function (type) { 2 if (type) { 3 return '示例6-1-1'; 4 } else { 5 throw new Error('sorry is Error!!!') 6 } 7 } 8 async function test() { 9 try { 10 let a = await fun(false); 11 console.log(a) 12 } catch (err) { 13 console.log(err); 14 return; 15 } finally { 16 console.log('我執行了!!!') 17 } 18 } 19 test();
1 /*示例6-3-4*/ 2 function fun(a, b) { 3 return a * b; 4 } 5 console.log(fun(1, 2), '函數聲明'); 6 7 let a = function (a, b) { 8 return a * b; 9 } 10 console.log(a(1, 2), '函數表達式'); //不能在初始化之前使用 11 let fun1 = new Function('a', 'b', 'return a*b'); 12 console.log(fun1(1, 2), '構造函數'); 13 14 /*示例6-3-5*/ 15 function f() { return 1; } 16 console.log(f()); // 第四個函數把第一個函數覆蓋 4 17 18 var f = new Function("return 2;"); 19 console.log(f()); // 第二個函數把第四個函數覆蓋 2 20 21 var f = function () { return 3; } 22 console.log(f()); // 第三個函數把第二個函數覆蓋 3 23 24 function f() { return 4; } 25 console.log(f()); // 第四個函數已經被覆蓋 3 26 27 var f = new Function("return 5;"); 28 console.log(f()); // 第五個函數把第三個函數覆蓋 5 29 30 var f = function () { return 6; } 31 console.log(f()); // 第六個函數把第五個函數覆蓋 6 32 33 /*示例6-3-6*/ 34 var k = 4; 35 window.onload = function () { 36 37 var k = 1; 38 39 function t1() { 40 var k = 2; 41 42 function test() { 43 return k; 44 } 45 console.info(test()); // 彈出 2 46 47 var test = function () { 48 return k; 49 }; 50 console.info(test()); // 彈出 2 51 52 var test = new Function("return k;"); // 每次執行的時候,動態的new,頂級作用域,無法獲得局部變量 53 console.info(test()); // 彈出 4 54 55 } 56 t1(); 57 };