JS中的async/await -- 异步隧道尽头的亮光

JS中的异步操做从最初的回调函数演进到Promise,再到Generator,都是逐步的改进,而async函数的出现仿佛看到了异步方案的终点,用同步的方式写异步。
asyncajax

原文连接promise

async函数

简单解释async函数就是Generator函数的语法糖。异步

Generator函数写法async

let promise = function (val){
    return new Promise(function (resolve, reject){
        setTimeout(()=>{
            console.log(val);
            resolve(val);
        },1000);
    });
};

let gen = function* (){
    let p1 = yield promise('1');
    let p2 = yield promise('2');
};

let genF = gen();

async函数写法函数

let promise = function (val){
    return new Promise(function (resolve, reject){
        setTimeout(()=>{
            console.log(val);
            resolve(val);
        },1000);
    });
};

let gen = async function (){
    let p1 = await promise('1');
    let p2 = await promise('2');
};

async函数是在Generator函数上进行的改进,语法上Generator函数的星号换成了async,yield换成了await。
而async也与Generator函数不一样:spa

  • 自带内置执行器,Generator函数须要依靠执行器,而async能够和普通函数同样,只须要一行
  • 相对Generator函数,async和await语义更清楚
  • 适用性强,yield后只能是Thunk函数和Promise对象,而await后能够是Promise对象和原始类型的值(数值、字符串、布尔型等)

async做用

寄予async函数的指望是但愿能够帮助咱们解决异步操做问题,因此须要搞清楚async函数的返回值是什么。code

async function asyncAwait() {
    return 'async await';
}

let a = asyncAwait();
console.log(a);

结果输出:对象

Promise {<resolved>: "async await"}

能够看出async函数返回的是一个Promise对象,若是函数中return一个直接量,async函数会封装成Promise对象返回,而若是没有返回值时,async函数会返回undefinedrem

Promise {<resolved>: undefined}

在没有结合await时,async函数会当即执行,返回一个Promise对象。字符串

await等待

await是个运算符,等待的结果是Promise对象或其余值,好比:

function func1() {
    return 'async';
}

async function func2() {
    return Promise.resolve('await');
}

async function asyncAwait() {
    let f1 = await func1();
    let f2 = await func2();
    console.log(f1, f2);
}

asyncAwait()

结果输出:

async await

await表达式的运算取决于等待的结果,若是它等到的不是一个Promise对象,那运算结果就是它等到的东西,
而若是它等到的是一个Promise对象,它会阻塞后面的代码,等着Promise对象resolve,而后获得resolve的值,做为表达式的运算结果。
async函数调用会封装在Promise中,这也是await须要在async函数中使用的缘由。

async/await链式处理

对于多个异步操做中,Promise的then能够解决多层回调问题。

function ajax(t) {
    return new Promise(resolve => {
        setTimeout(() => resolve(t + 200), t);
    });
}

function step1(t) {
    console.log(`step1 in ${t}ms`);
    return ajax(t);
}

function step2(t) {
    console.log(`step2 in ${t}ms`);
    return ajax(t);
}

function step3(t) {
    console.log(`step3 in ${t}ms`);
    return ajax(t);
}

function submit(){
    console.time('submit');
    step1(200)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}ms`);
            console.timeEnd("submit");
        });
}

submit();

async函数实现:

function ajax(t) {
    return new Promise(resolve => {
        setTimeout(() => resolve(t + 200), t);
    });
}

function step1(t) {
    console.log(`step1 in ${t}ms`);
    return ajax(t);
}

function step2(t) {
    console.log(`step2 in ${t}ms`);
    return ajax(t);
}

function step3(t) {
    console.log(`step3 in ${t}ms`);
    return ajax(t);
}

async function submit(){
    console.time('submit');
    const t1 = 200;
    const t2 = await step1(t1);
    const t3 = await step2(t2);
    const result = await step3(t3);
    console.log(`result is ${result}`);
    console.timeEnd('submit');
}

submit();

结果输出:

step1 in 200ms
step2 in 400ms
step3 in 600ms
result is 800
submit: 1209.85107421875ms

而若是需求变动,每一步的参数都是以前步骤的结果后,async函数能够写成:

function ajax(t) {
    return new Promise(resolve => {
        setTimeout(() => resolve(t + 200), t);
    });
}

function step1(t1) {
    console.log(`step1 in ${t1}ms`);
    return ajax(t1);
}

function step2(t1, t2) {
    console.log(`step2 in ${t1}ms,${t2}ms`);
    return ajax(t1 + t2);
}

function step3(t1, t2, t3) {
    console.log(`step3 in ${t1}ms,${t2}ms,${t3}ms`);
    return ajax(t1 + t2 + t3);
}

async function submit(){
    console.time('submit');
    const t1 = 200;
    const t2 = await step1(t1);
    const t3 = await step2(t1, t2);
    const result = await step3(t1, t2, t3);
    console.log(`result is ${result}`);
    console.timeEnd('submit');
}

submit();

结果输出:

step1 in 200ms
step2 in 200ms,400ms
step3 in 200ms,400ms,800ms
result is 1600
submit: 2210.47998046875ms

async/await注意点

  • async用来申明里面包裹的内容能够进行同步的方式执行,await则是进行执行顺序控制,每次执行一个await,阻塞代码执行等待await返回值,而后再执行以后的await。
  • await后面调用的函数须要返回一个promise。
  • await只能用在async函数之中,用在普通函数中会报错。
  • await命令后面的Promise对象,运行结果多是rejected,因此最好把await命令放在try...catch代码块中。

async/await try/catch写法

async function asyncAwait() {
    try {
        await promise();
    } catch (err) {
        console.log(err);
    }
}

// 另外一种写法
async function asyncAwait() {
    await promise().catch(function (err){
        console.log(err);
    });
}

总结

async/await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案,当你深刻了解原理后会发现仿佛看到了异步回调隧道的尽头亮光。

相关文章
相关标签/搜索