async、await相比原生promise的有优势:

1.更加简洁,await一个promise即可,那么会自动返回这个promise的resolve值,无需在then函数的回调中手动取值,彻底解决了回调

//Promise方式
function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('done!'), 1000)
})
promise.then((res) => {
console.log('object :', res);
})
}
f()
//async、await
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('done!'), 1000)
})
let result = await promise // 直到promise返回一个resolve值(*)
console.log('object :', result);
}
f()

2.避免了then链式调用的,没有设置失败回调而导致异常被抛出到then链的末端,而导致被忽略,向下面代码一样,如果then没有设置失败回调,那么默认的失败回调会将异常抛给下一个then函数的失败回调,如果末端没有一个catch函数。那么异常就会丢失,问题是如果catch代码中的异常处理代码又有异常抛出呢,那么这个异常只能在下一个then中捕获,这是容易被忽略的错误

//promise
let p = new Promise((resolve, reject) => {
reject()
})
p.then().then().catch()

async任意一个await出现了异常,await会自动抛出reject,并且程序会被停止,异常统一在try-catch块可以捕获而不会出现捕获链无限延长的问题

//async、await
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject('done!'), 1000)
})
try {
let result = await promise // 直到promise返回一个resolve值(*)
} catch (error) {
console.log('object :', error);
}
}
f()

3.then链式流中,数据访问不能很自然的跨层访问

MongoClient.connect(url + db_name).then(db=> {
return db.collection('blogs');
}).then(coll=> {
return coll.find().toArray();
}).then(blogs=> {
console.log(blogs.length);
}).catch(err=> {
console.log(err);

先连接数据库MongoClient.connect()返回一个Promise,然后在then()方法里获得数据库对象db,然后再获取到coll对象再返回。在下一个then()方法获得coll对象,然后进行查询,查询结果返回,逐层调用then()方法,形成一个Promise链。

这时候我们有一个需求,第三个then(blogs => {})中我们只能获取到查询的结果blogs,而不能使用上面的db对象和coll对象。这个时候,如果要打印出blogs列表后,要关闭数据库db.close()怎么办?

两种处理方式:

1.使用then嵌套

MongoClient.connect(url + db_name).then(db=> {
let coll = db.collection('blogs');
coll.find().toArray().then(blogs=> {
console.log(blogs.length);
db.close();
}).catch(err=> {
console.log(err);
});
}).catch(err=> {
console.log(err);

问题:

这会打断Promise链,导致then的回调地狱,而且导致在每一个then中都需要手动捕获异常,因为then没成链,不能自然传递异常

2.每个then()方法里都将db传过来

MongoClient.connect(url + db_name).then(db=> {
return {db:db,coll:db.collection('blogs')};
}).then(result=> {
return {db:result.db,blogs:result.coll.find().toArray()};
}).then(result=> {
return result.blogs.then(blogs=> { //注意这里,result.coll.find().toArray()返回的是一个Promise,因此这里需要再解析一层
return {db:result.db,blogs:blogs}
})
}).then(result=> {
console.log(result.blogs.length);
result.db.close();
}).catch(err=> {
console.log(err);

问题:

我们在then方法中,都将db和其他结果合并成一个对象,特别需要注意的是,如果传递的值含有promise,那么还需要多做一层解析,也就是需要单独给予一个then函数进行处理,况且每次都要传递一个多余的对象(对于到达实际使用地方这段路径,这个对象是不需要使用的)

async、await方案:

let getBlogs = async function(){
let db = await MongoClient.connect(url + db_name);
let coll = db.collection('blogs');
let blogs = await coll.find().toArray();
db.close();
return blogs;
}; getBlogs().then(result=> {
console.log(result.length);
}).catch(err=> {
console.log(err);

这里await解决了then链的问题,使得then跨层访问的问题从根本上被解决了,因为await的promise的resolve值被置于同一个作用域,可以随意访问

4.使得原本异步非阻塞的表达方式,变成了更加同步阻塞的代码,这得益于ES6中生成器和迭代器,赋予js函数的魔力,本质上,async、await是生成器和迭代器以及Promise结合的语法糖,它使得promise之前设计缺陷被更好地修正,目前看来,async、await,是异步的终极解决方案之一

async function basicDemo() {
let result = await Math.random();
console.log(result);
} basicDemo();

await由于自动返回了resolve的值,无需then,我们甚至没有感知到异步的存在,他将异步从语法层面上进行了同步化

async、await使用注意事项:

1.await虽然可以像Promise.resolve作用域很多类型的数据,但它的主要意图是用来等待Promise对象被resolved,如果await是非promise值,那么会被立即执行

2.async函数将返回值自动包装成一个promise,就像Promise.resolve一致的行为

3.await必须在async函数上下文,也就是如下代码的区别

// 正常 for 循环
async function forDemo() {
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i ++) {
await arr[i];
}
}
forDemo();//正常输出
// 因为想要炫技把 for循环写成下面这样
async function forBugDemo() {
let arr = [1, 2, 3, 4, 5];
arr.forEach(item => {
await item;
});
}
forBugDemo();// Uncaught SyntaxError: Unexpected identifier

4.小心自己的并行处理,也许不小心就将ajax的并发请求发成了阻塞式同步的操作,理解这句话的核心是: await若等待的是promise,那么程序就会在此处等到promise的resolved,然后继续往下,看下面例子,这里第一个sleep会等待自身resolved完成才会往下,如果我们可以让这些函数并行,同时保持await的特性,那么效率会大大提高

function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('request done! ' + Math.random());
}, second);
})
} async function bugDemo() {
await sleep(1000);
await sleep(1000);
await sleep(1000);
console.log('clear the loading~');
} bugDemo();

正确的姿势是:

async function correctDemo() {
let p1 = sleep(1000);
let p2 = sleep(1000);
let p3 = sleep(1000);
await Promise.all([p1, p2, p3]);//这里单独await每一个promise也是一样的效果
console.log('clear the loading~');
}
correctDemo();// clear the loading~

async和await对promise异步方案的改进,以及使用注意事项的更多相关文章

  1. async和await关键字实现异步编程

    async和await关键字实现异步编程 异步编程   概念 异步编程核心为异步操作,该操作一旦启动将在一段时间内完成.所谓异步,关键是实现了两点:(1)正在执行的此操作,不会阻塞原来的线程(2)一旦 ...

  2. C#的多线程——使用async和await来完成异步编程(Asynchronous Programming with async and await)

    https://msdn.microsoft.com/zh-cn/library/mt674882.aspx 侵删 更新于:2015年6月20日 欲获得最新的Visual Studio 2017 RC ...

  3. async/await actor promise 异步编程

    Python协程:从yield/send到async/await http://blog.guoyb.com/2016/07/03/python-coroutine/ Async/Await替代Pro ...

  4. promise、async、await、settimeout异步原理与执行顺序

    一道经典的前端笔试题,你能一眼写出他们的执行结果吗? async function async1() { console.log("async1 start"); await as ...

  5. koa2 使用 async 、await、promise解决异步的问题

    koa代码编写上避免了多层的嵌套异步函数调用 async await来解决异步 - async await 需要依赖于promise 三主角: __函数前面 async, 内部才能await,要想aw ...

  6. async generator promise异步方案实际运用

    es7 async方案 /******************async***********************/ var timeFn=function(time){ return new P ...

  7. async和await是如何实现异步编程?

    目录 异步编程样例 样例解析 浅谈Promise如何实现异步执行 参考 1.异步编程样例 样例: // 等待执行函数 function sleep(timeout) { return new Prom ...

  8. 温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法

    什么是异步编程(Async/Await) Async/Await本质上是通过编译器实现的语法糖,它让我们能够轻松的写出简洁.易懂.易维护的异步代码. Async/Await是C# 5引入的关键字,用以 ...

  9. 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

    一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...

随机推荐

  1. commitizen规范代码提交

    转载链接:https://www.jianshu.com/p/bd712e42f2e9 参考链接:https://segmentfault.com/a/1190000009048911 平时提交的变动 ...

  2. linux搜索log文件的内容

    日志一般是记载每天所做的工作.在计算机科学中,日志是指服务器等电脑设备或软件的运作记录(Server log).在电脑设备和软件出现问题时,日志是我们在排查问题的一个重要依据.查询日志是用户记录从客户 ...

  3. python的深浅拷贝-成为马老师的弟子

    参考链接 骏马金龙 前提 想要了解深浅拷贝之前必须要知道可变和不可变类型,和他们的特性 不可变类型 数字 字符串 元组 不可变集合 特性:改变值,会创建新的内存空间存储数据 可变类型 列表 字典 可变 ...

  4. 折腾linux随笔 之 关闭Budgie默认自动隐藏应用的菜单栏 与 Gnome系桌面应用菜单无内容解决

    关闭Budgie默认自动隐藏应用菜单栏 首选项 -> 设置 -> 通用辅助功能 -> 打开 始终显示通用辅助菜单 后的开关 -> 注销桌面重新登录. done. 解决Gnome ...

  5. http内网转发

    package main import ( "io" "log" "net/http" "strings" ) func ...

  6. “sgen.exe”未能运行。文件名或扩展名太长

    问题 创建项目后无法运行 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 MSB6003 指定的任务可执行文件"sgen.exe"未能运行.System.Component ...

  7. C#使用post方式提交json数据

    尝试了一天,尝试了各种方法,一下方法最直接方便. //地址 string _url = "https://www.dXXXayup.ink/api/User/Login"; //j ...

  8. win10系统本地iis或nginx服务器部署vue.js项目

    1.前端框架一般依赖node.js,我们首先要安装node.js.请参考: http://www.cnblogs.com/wuac/p/6381819.html to:安装好node.js后npm也安 ...

  9. PIE SDK剔除栅格块算法

    1.算法功能简介 剔除栅格块即剔除栅格小斑块功能.一幅影像图层某一区域存在碎小斑块,需要对其按照一定的条件进行剔除. PIE支持剔除栅格快算法功能的执行,下面对该算法功能进行介绍. 2.算法功能实现说 ...

  10. Java常用类StringBuffer详解

    内容多为最近学习的自我总结,可能有些地方写的不严谨,甚至会有错误的地方,仅供参考,如发现错误敬请指出,谢谢! 灰色字体为补充扩展内容,多为帮助自己理解. StringBuffer概述: 线程安全的可变 ...