1 前情摘要

前段时间时间进行项目开发,需求安排不是很合理,导致一直高强度的加班工作,这一个月不是常说的996,简直是936,还好熬过来了。在此期间不是刚学会了es6的promise,在项目有用到promise的就一直都在用promise,爽的不要不要的,哈哈,项目到了最终阶段,不是很忙了,就开始自己的学习之路,好啦,废话到此为止,开始~

2 含义

关于异步操作,在es6之前,一直都是

回调函数,

事件监听,

发布/订阅

promise对象

(摘自es6的Generator函数的异步应用),这四个为主,再加上es6出来的promise对象以及后来的Generator函数,都可以解决异步编程。es7引入的async函数,使得异步操作变得更加方便

async函数,就是Generator 函数的语法糖,基于Generator 函数而来的,只是为了书写代码时更加流畅,增强代码的可读性。async的返回值就是个promise对象,进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

3 基本语法

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

async function demo(val) {
let result = await `hello,${val}`;
return result;
}
demo('peter').then((val)=>{console.log(`${val},哈哈哈哈`)}) // hello,peter,哈哈哈哈
console.log(demo('peter')) // Promise{<pending>}

上述就是async的最基本语法,这看起来和普通的函数没有什么区别,只是多了两个关键字async和await,以及返回的promise的实例。

async

是异步操作的说明,在普通函数名前面加上async代表了是一个异步操作,async函数返回一个 Promise 对象,async函数return语句返回的值,会成为then方法回调函数的参数

  async function f() {
return 123
}
f().then(v => console.log(v)) // 123

将当于

  async function f() {
return await new Promise(function(resolve){
resolve(123)
})
}
f().then(v => console.log(v)) // 123

也将当于

  async function f() {
return await Promise.resolve('123')
}
f().then(v => console.log(v))

将async的return的值作为参数传递给then函数。

await

await 可以理解为是 async wait 的简写。await 必须出现在 async 函数内部,不能单独使用,否则会报错

    function foo() {
await 123;
}
foo(); //Uncaught SyntaxError: await is only valid in async function

这就是没有在函数名前面声明async报的错,相反的,声明了async,没有使用await不会报错

await 后面可以跟任何的JS 表达式。虽然说 await 可以是很多类型的东西,但是它最主要的意图是用来等待 Promise 对象的状态被 resolved。

  • async function foo() {}// 函数声明
  • const foo = async function () {};// 函数表达式
  • let obj = { async foo() {} };

    obj.foo().then(...)// 对象的方法
  • class Foo {// Class 的方法

    constructor() { }

    async foo(name) { }

    }
  • const foo = async () => {};// 箭头函数

如果await的是promise对象会造成异步函数停止执行并且等待promise的解决,如果等的是正常的表达式则立即执行。

另外:await命令后面的 Promise 对象如果变为reject状态,则reject的参数会被catch方法的回调函数接收到。

async function f() {
await Promise.reject('出错了');
} f()
.then(v => console.log(v))
.catch(e => console.log(e)) // 出错了

ps: 任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。

async function f() {
await Promise.reject('出错了');
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
.catch(e => console.log(e)) // 出错了

上述代码在await的时候,实行了promise的reject方法,会直接终端执行,直接实行reject的方法

4 错误处理/异常处理

防止出错的方法,也是将其放在try...catch代码块之中,这样又能实行剩下的部分。

function time(ms){
if(ms<3000){
setTimeout(()=>{
console.log('ms',ms)
return ms
},ms)
}else{
return Promise.reject('出错了')
}
}
async function f() {
try {
let a = await time(1000)
let b = await time(2000)
let c = await time(3000)
} catch(e) {
console.log('e',e) // 'e' 出错了
}
return await('hello world');
}
f().then(val=>{
console.log(val) // hello world
}).catch(val=>{
console.log(val)
})

先报错‘出错了’,再‘hello world’ 再依次打印出‘1000’,‘2000’

因为有了reject之后,就无法往下进行,但是最后return是返回一个resolve的值给then()

5 注意点

有的注意点上面已经提到了,先总结如下:

  • await 必须出现在 async 函数内部,不能单独使用,否则会报错。

  • await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中,多个await也是如此。

  • 多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发,所谓的继发就是,不相互关联的异步操作,比如第一个异步的返回值给第二个异步这样的例子。

    function time(ms){
    return new Promise((resolve,reject)=>{
    setTimeout(function(){
    resolve()
    },ms)
    })
    }
    async function f() {
    try {
    let a = time(1000)
    let b = time(2000)
    await Promise.all([a,b]); // 不加Promise.all()的话,3s才实行完,加上Promise.all()的话,2s实行完
    console.log('~~~')
    } catch(e) {
    console.log('e',e) // 'e' 出错了
    }
    }
    f()
  • await必须在async函数的上下文中的作用域中

    //for 循环
    async function a() {
    let arr = [1, 2, 3, 4, 5];
    for (let i = 0; i < arr.length; i ++) {
    await arr[i];
    }
    }
    a();
    // forEach循环
    async function b() {
    let arr = [1, 2, 3, 4, 5];
    arr.forEach(item => {
    await item;
    });
    }
    b();// Uncaught SyntaxError: Unexpected identifier

原因就是forEach就是一个单独的作用域,会报错。

6 总结

async-await函数就是为了简化异步操作的一种方式,大部分就是结合promise使用,离开不了promise,就像那个并发实行需要使用promise的方法。妥善使用async-await,会给自己对异步操作带来很大的便利,另外,感谢一位博主的文章,让我更快的理解async-await函数。

如果本文有什么不对的地方,欢迎指出,谢谢,大家一起进步加油。我把笔记放到github了,如果满意的话给个star~

参考文献

es6学习笔记-async函数的更多相关文章

  1. js-ES6学习笔记-async函数(3)

    1.await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中. 2.多个await命令后面的异步操作,如果不存在继发关系,最好 ...

  2. js-ES6学习笔记-async函数(2)

    1.async函数返回一个 Promise 对象. async函数内部return语句返回的值,会成为then方法回调函数的参数. async function f() { return 'hello ...

  3. js-ES6学习笔记-async函数

    1.async 函数是 Generator 函数的语法糖.前文有一个 Generator 函数,依次读取两个文件. var fs = require('fs'); var readFile = fun ...

  4. ES6学习之Async函数

    定义:Async函数是一个异步操作函数,本质上,Async函数是Generator函数的语法糖.async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await ...

  5. ES6学习笔记(函数)

    1.函数参数的默认值 ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面. function log(x, y = 'World') { console.log(x, y); } log(' ...

  6. es6学习笔记6--Generator 函数

    基本概念 Generator函数有多种理解角度.从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态. 执行Generator函数会返回一个遍历器对象,也就是说,Gen ...

  7. ES6 学习笔记之三 函数参数默认值

    定义函数时为参数指定默认值的能力,是现代动态编程语言的标配.在ES6出现之前,JavaScript是没有这种能力的,框架为了实现参数默认值,用了很多技巧. ES6 的默认参数值功能,与其他语言的语法类 ...

  8. ES6学习笔记(6)----函数的扩展

    参考书<ECMAScript 6入门>http://es6.ruanyifeng.com/ 函数的扩展 函数的默认值 : ES6可以为函数指定默认值 (1)指定默认值的两种方式 a.函数参 ...

  9. es6学习笔记--箭头函数

    基本用法 ES6允许使用“箭头”(=>)定义函数. var f = v => v; 上面的箭头函数等同于: var f = function(v) { return v; }; 如果箭头函 ...

随机推荐

  1. eclipse 安装svn和gradle

    公司项目用的eclispe  svn和gradle 所以需要配置 SVN教程:https://blog.csdn.net/jieshaowang1229/article/details/5159499 ...

  2. 云计算一:VMware workstation的安装和使用教程

    VMware workstation的安装和使用教程 一.VMware 安装 1.从网上找到VMware的安装包以及要安装的映像文件,下载到本地,然后备份一份存储到百度云盘. 链接:http://pa ...

  3. 《T-SQL查询》读书笔记Part 3.索引的基本知识

    索引优化是查询优化中最重要的一部分,索引是一种用于排序和搜索的结构,在查找数据时索引可以减少对I/O的需要:当计划中的某些元素需要或是可以利用经过排序的数据时,也会减少对排序的需要.某些方面的优化可以 ...

  4. Selenium2Lib库之键盘常用关键字实战

    Press Key关键字 按F5 查看Press Key关键字的说明,如下图: Press Key关键字是用于通过键盘模拟由定位器确定的元素的用户按键.‘值’是单个字符,字符串或数值的ASCII码的“ ...

  5. MySQL 8 新特性之持久化全局变量的修改

    在8之前的版本中,对于全局变量的修改,其只会影响其内存值,而不会持久化到配置文件中.数据库重启,又会恢复成修改前的值.从8开始,可通过SET PERSIST命令将全局变量的修改持久化到配置文件中. 试 ...

  6. Linux之SSH密钥认证

    1.SSH协议的认识 SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定:SSH 为建立在应用层基础上的安全协议.SSH 是目前 ...

  7. nginx常用配置系列-反向代理

    接上篇,反向代理的原理与用途很多地方有讲,用文字说再多可能也表达不清楚,下面贴一张拓扑图,介绍下什么叫反向代理 以上图有两种情景 1. 访问者的客户端是 local ,要访问baidu的服务器,bai ...

  8. git merge 撤销与git 回滚

    git merge提交后恢复 http://blog.psjay.com/posts/git-revert-merge-commit/ git回滚 https://www.jianshu.com/p/ ...

  9. Pat1108: Finding Average

    1108. Finding Average (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue The b ...

  10. Linux修改本机/etc/hosts的hostName

    1.Linux修改本机别名/etc/hosts的hostName后经常不生效解决 Linux修改本机别名/etc/hosts的hostName后经常不生效, 比如我们/etc/hosts的内容如下: ...