async、await相比原生promise的有优点:javascript
1.更加简洁,await一个promise便可,那么会自动返回这个promise的resolve值,无需在then函数的回调中手动取值,完全解决了回调java
//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中捕获,这是容易被忽略的错误ajax
//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链式流中,数据访问不能很天然的跨层访问promise
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()怎么办?dom
两种处理方式:异步
1.使用then嵌套async
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没成链,不能天然传递异常ide
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~