JavaScript Async/Await

异步编程是 Web 前端工程师最难处理的问题之一,自从 Ajax 的出现后,异步编程越来越普遍,现在前端 MV* 框架的兴起让前端完全和后端分离开来,使得异步编程已经司空见惯,异步编程也是从回调函数、到事件的监听、到 Promise、到 Generator 函数,它们都在解决同样一个问题,让异步编程的调用更佳的“扁平”化,让前端工程师在异步编程中更佳容易和优美的解决问题,终于 Async/Await 出现了。

Async/Await 是什么

Async/Await 是编写异步程序的新方式,它实际上是基于 Promise 来实现的,它会让异步的代码写起来和同步代码一样。Node 已经在 7.6 版本开始支持 Async/Await,并且它已经在 ES7 的新特性中出现。

如何使用

让我们看看它到底是如何使用的,它采用了什么样神奇的语法糖。在揭开它的面纱前,我们先看看一个使用 Promise 的异步编程:我们用 axios 模块异步获取一条数据:

function getData() {
    return axios.get('http://domain/path')
        .then(resp => {
            return resp;
        });
}

getData();

如果使用 Async/Await:

async function getData() {
    let resp = await axios.get('http://domain/path');

    return resp;
}

getData();

第一种写法我们已经很熟悉,采用 Promise 的写法,将移步的调用编程了链式的写法,让复杂的回调更佳的清晰。让我们再看看第二种 Async/Await 写法:

  • 函数前增加关键字 async,在函数体内使用了 await 关键字,await 当然它也只能声明在函数体内。该函数会隐式地返回一个 Promise 对象,函数体内的 return 值,将会作为这个 Promise 对象 resolve 时的参数。
  • await axios.get() 会让函数等到 axios.get() 返回的 Promise 对象 resolve 之后触发。

使用 Async/Await 的 6 大优势

我们参考了 Mostafa Gaafar 高级全栈工程师的文章,来解释一下 Async/Await 如下 6 大优势:

让代码更佳的简约

回顾我们上面的代码实例中,很明显我们的代码简洁清晰了很多。我们不用写 then ,不需要创建一个匿名函数来处理返回值,或者也不需要把一个数据赋给一个我们不需要的值。我们甚至是避免了代码的嵌套。这些小的优势将会在下面的代码中更加明显。

更容易处理错误

Async/Await 最终让以同样的方式来处理同步和异步的错误成为了可能,让 try/catch 更好的使用。下面的实例中,使用 Promise,来处理异步编程的错误捕获,由于程序是异步的最外面一层 try/catch,它无法捕获到 Promise 内部发生的错误,我们只能再嵌套一层 try/catch 来解决:

function getData() {
    
    try {
        axios.get('http://domain/path')
            .then(resp => {
                try {
                    let json = JSON.parse(resp);
                }
                catch (err) {
                    console.log(err);
                }

                return json;
            });
    }
    catch (err) {
        console.log(err);
    }
}

我们看看使用了 Async/Await 的异步编程是如何处理错误的:

async function getData() {
    let data;

    try {
        data = JSON.parse(await axios.get('http://domain/path'));
    }
    catch (err) {
        console.log(err);
    }

    return data;
}

更容易处理条件判别

想象一下这样的业务逻辑:我们先要获取一些数据,然后通过获取到的数据来判断是否继续获取更多的详细数据:

function getData() {
    return axios.get('http://domain/path').then(resp => {
        if(resp && resp.data && resp.data.yes) {
            return axios.get('http://domain/path1').then(resp1 => {
                return resp1;
            })
        }
        else {
            return resp
        }
    });
}

这样的写法会让你很头疼,嵌套太多会导致很多变量的遗失,让逻辑难以处理。接下来让我们看看 Async/Await 编程如何让代码更佳容易阅读:

async function getData() {
    let data = await axios.get('http://domain/path');

    if(data.yes) {
        let data1 = await axios.get('http://domain/path1');
        return data1;
    }
    else {
        return data;
    }
}

更容易处中间值

你可能会发现自己会有这样的情况:你调用了 promise1 然后将它返回给 promise2,最后又奖两个 promise 的结果都返回给 promise3。你的代码很可能会写成这样:

function getData() {
    return promise1()
        .then(value1 => {
            return promise2(value1)
            .then(value2 => {        
                return promise3(value1, value2)
        })
    })
}

同样的逻辑我们用 Async/Await 编写:

async function getData() {
    const value1 = await promise1()
    const value2 = await promise2(value1)
    return promise3(value1, value2)
}

错误堆栈信息

想象一下通过多个链式调用 Promise :

function getData() {
    return callAPromise()
        .then(() => callAPromise())
        .then(() => callAPromise())
        .then(() => callAPromise())
        .then(() => callAPromise())
        .then(() => {
        throw new Error("oops");
        });
}

getData().catch(err => {
    console.log(err);
    // output
    // Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
})

此链条的错误堆栈信息并没用线索指示错误到底出现在哪里。更糟糕的是,它会误导我们:

Debugging

最后,也是最重要的优势是,使用 Async/Await 非常容易调试,调试 Promise 有如下两个不好的地方:

  • 我们不能在返回表达式的箭头函数中设置断点;
  • 如果你在 .then 中设置断点,然后通过 step-over 的方式进行调试,调试器不会移动到下一步,因为它只能通过同步的方式移动到下一步。

但是如果我们使用 Async/Await 你可以一步一步的正常的使用调试。

最后

Async/Await 是 JavaScript 中添加的具有革命性特征之一,它让你更容易的进行异步的编程。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容