异步问题除了可以使用前面学到的Promise来解决之外,我们还可以用async/await来搞定。

async/await是ES7中新增的新语法。虽然现在最新的chrome浏览器已经支持了该语法,但是在实际使用中,我们需要在构建工具中配置对该语法的支持才能放心使用。因此如果你目前的开发经验还没有涉及到构建工具的使用,你可以暂时跳过该语法的学习。

接下来的知识会配合ES6的语法进行讲解,如果你还没有学习ES6的语法,也可以暂时跳过

在函数声明的前面,加上关键字async,这就是async的具体使用。

async function fn() {
    return 30;
}

// 或者
const fn = async () => {
    return 30;
}

我们可以打印出fn函数的运行结果

console.log(fn());

// result
Promise = {
    __proto__: Promise,
    [[PromiseStatus]]: "resolved",
    [[PromiseValue]]: 30
}

发现fn函数运行返回的是一个标准的Promise对象。因此我们可以猜想到,async其实是Promise的一个语法糖,目的是为让写法更加简单。因此我们也可以使用Promise的相关语法来处理后续的逻辑。

fn().then(res => {
    console.log(res);  // 30
})

await的含义为等待。意思就是代码需要等待await后面的函数运行完并且有了返回结果之后,才继续执行下面的代码。这正是同步的效果。

但是我们需要注意的是,await关键字只能在async函数中使用。并且await后面的函数运行后必须返回一个Promise对象才能实现同步的效果。

当我们使用一个变量去接收await的返回值时,该返回值为Promise中resolve传递出来的值(也就是PromiseValue)。

// 定义一个返回Promise对象的函数
function fn() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(30);
        }, 1000);
    })
}

// 然后利用async/await来完成代码
const foo = async () => {
    const t = await fn();
    console.log(t);
    console.log('next code');
}

foo();

// result:
// 30
// next code

运行这个例子我们可以看出,当在async函数中,运行遇到await时,就会等待await后面的函数运行完毕,而不会直接执行next code。

如果我们直接使用then方法的话,想要达到同样的结果,就不得不把后续的逻辑写在then方法中。

const foo = () => {
    return fn().then(t => {
        console.log(t);
        console.log('next code');    
    })
}

foo();

很显然如果使用async/await的话,代码结构会更加简洁,逻辑也更加清晰。

异常处理

在Promise中,我们知道是通过catch的方式来捕获异常。而当我们使用async时,则通过try/catch来捕获异常。

function fn() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('some error.');
        }, 1000);
    })
}

const foo = async () => {
    try {
        await fn();
    } catch (e) {
        console.log(e);  // some error
    }
}

foo();

如果有多个await函数,那么只会返回第一个捕获到的异常。

function fn1() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('some error fn1.');
        }, 1000);
    })
}
function fn2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('some error fn2.');
        }, 1000);
    })
}

const foo = async () => {
    try {
        await fn1();
        await fn2();
    } catch (e) {
        console.log(e);  // some error fn1.
    }
}

foo();

在实践中我们遇到异步场景最多的就是接口请求,那么这里就以jquery中的$.get为例简单展示一下如何配合async/await来解决这个场景。

// 先定义接口请求的方法,由于jquery封装的几个请求方法都是返回Promise实例,因此可以直接使用await函数实现同步
const getUserInfo = () => $.get('xxxx/api/xx');

const clickHandler = async () => {
    try {
        const resp = await getUserInfo();
        // resp为接口返回内容,接下来利用它来处理对应的逻辑
        console.log(resp);

        // do something
    } catch (e) {
        // 处理错误逻辑
    }
}

为了保证逻辑的完整性,在实践中try/catch必不可少。

results matching ""

    No results matching ""