出现原因
Promise 太麻烦了
function divPromise (num) {return new Promise((resolve, reject) => {$(`div:nth-child(${num})`).fadeIn(750, () => {resolve()})})}divPromise(1).then(() => {return divPromise(2)}).then(() => {return divPromise(3)})//改造下async function divLoading () {for (let i = 1; i <= 3; i++) {await divPromise(i)}}divLoading()
概念
作用
是用于等待异步操作结束并可以接受到Promise对象中传入到resolve()里的数据
语法
async function(){let 变量名 = await promise对象;}
特点
异步函数的返回值是一个promise对象,会将该函数return 后的数据作为resolve函数的实际参数
async function 函数名(){return 数据;// 该数据会作为返回的promise对象(resolve()的实际参数)}函数名().then((data) => {console.log(data); //data就是上面return的数据})
可以额外使用await关键字,普通函数中不能使用await
- 异步函数内部可以写任意代码,不仅仅是异步代码
async
执行流程
普通执行流程(同步)
异步函数的内部代码执行过程和普通的函数是一致的,默认情况下也是会被同步执行。且异步函数内部可以写任意代码,不仅仅是异步代码console.log(1);async function demo () {console.log(2);setTimeout(() => {console.log(3);}, 100);console.log(4);}demo();console.log(5);//1 2 4 5 3
有返回值的执行流程
1、return 不是Promise对象

返回值一定是Promise,会被包裹到Promise.resolve( )中,因此可以直接接.then(res),res就是return 的结果(没有就是undefined) ```javascript const promise = foo() promise.then(res => {
})
<a name="Cxf36"></a>#### 2、return 实现then的对象return 的是一个对象,并且实现了then方法,这样就会直接执行这个then方法,然后把结果传递到后面的then<br /><a name="f3jCH"></a>#### 3、return Promise对象如果我们的异步函数的返回值是Promise 对象,那么后面Promise的状态会由这个Promise对象决定,是执行then还是执行catch<a name="Amxrw"></a>### 抛出异常的执行流程在普通函数中,当运行到 throw 抛出异常,就会报错并终止整个程序继续运行;而async 异步函数,运行到 throw 抛出异常,不会报错,不会终止整个程序继续运行,而是会作为Promise的reject来传递,后面可以用(必须要用)catch来捕获异常<br /><a name="zUCXa"></a># await只能用在异步函数 async 里面<a name="udg18"></a>## 1、后面跟 成功的Promise- await关键字的特点- 通常使用await是后面会跟上一个表达式,这个表达式会返回一个Promise ;- 那么await会等到Promise的状态变成fulfilled状态,之后继续执行异步函数;- 也可以直接写new Promise```javascriptasync function foo () {const res = await new Promise(resolve => {resolve('res')})console.log(res);}foo() //'res'
2、后面跟 普通的值
如果await后面是一个普通的值,那么会直接返回这个值;
async function foo () {const res = await 123console.log(res);}foo() //123
3、后面跟 实现then的对象
如果await后面是一个thenable的对象,那么会根据对象的then方法调用来决定后续的值;
4、后面跟 失败的Promise
会直接跳出运行,把结果返回给外面(且当前异步函数后面不执行了),需要用catch接收
也可以通过try catch语句捕获
限制
// 不允许:await 出现在箭头函数中function foo() {const syncFn = () => {return await Promise.resolve('foo');};console.log(syncFn());}// 不允许:await 出现在同步函数表达式中function baz() {const syncFn = function() {return await Promise.resolve('baz');};console.log(syncFn());}
停止和恢复执行
JavaScript 运行时在碰到 await 关键字时,会记录在哪里暂停执行。
等到 await 右边的值可用了,JavaScript 运行时会向消息队列中推送一个任务,这个任务会恢复异步函数的执行。
async function foo() {console.log(await Promise.resolve('foo'));}async function bar() {console.log(await 'bar');}async function baz() {console.log('baz');}foo();bar();baz();// baz// bar// foo
async function foo() {console.log(2);console.log(await Promise.resolve(8));console.log(9);}async function bar() {console.log(4);console.log(await 6);console.log(7);}console.log(1);foo();console.log(3);bar();console.log(5);// 1 2 3 4 5 8 9 6 7
顺序执行、并行执行
// 定义一个延迟执行async function randomDelay(id) {// 延迟 0~1000 毫秒const delay = Math.random() * 1000;return new Promise((resolve) => setTimeout(() => {console.log(`${id} finished`);resolve();}, delay));}// 顺序执行async function foo() {const t0 = Date.now();await randomDelay(0);await randomDelay(1);await randomDelay(2);await randomDelay(3);await randomDelay(4);console.log(`${Date.now() - t0}ms elapsed`);}foo();// 0 finished// 1 finished// 2 finished// 3 finished// 4 finished// 877ms elapsed// 并行执行async function foo() {const t0 = Date.now();const promises = Array(5).fill(null).map((item, index) => randomDelay(index));for (const p of promises) {console.log(`awaited ${await p}`);}/*相当于const p0 = randomDelay(0);const p1 = randomDelay(1);const p2 = randomDelay(2);const p3 = randomDelay(3);const p4 = randomDelay(4);await p0;await p1;await p2;await p3;await p4;*/console.log(`${Date.now() - t0}ms elapsed`);}foo();// 1 finished// 2 finished// 4 finished// 3 finished// 0 finished// awaited 0// awaited 1// awaited 2// awaited 3// awaited 4// 645ms elapsed
性能
Promise与异步函数的功能有相当程度的重叠,但它们在内存中的表示则差别很大。
Promise:
JavaScript 引擎会在创建Promise时尽可能保留完整的调用栈。
在抛出错误时,调用栈可以由运行时的错误处理逻辑获取,因而就会出现在栈追踪信息中。
当然,这意味着栈追踪信息会占用内存,从而带来一些计算和存储成本。
异步函数async/await:
JavaScript 运行时可以简单地在嵌套函数中存储指向包含函数的指针,就跟对待同步函数调用栈一样。
这个指针实际上存储在内存中,可用于在出错时生成栈追踪信息。
这样就不会像之前的例子那样带来额外的消耗,因此在重视性能的应用中是可以优先考虑的。
实例:Ajax请求
//根据url生成promisefunction ajaxPromise (url) {return new Promise(function (resolve) {$.ajax({url,success: function (data) {resolve(data)}})})}
promise then 方法
ajaxPromise(url).then(data => {//拿到data数据})
async await 方法
let data = await ajaxPromise(url);console.log(count);
