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