细说 async/await 相较于 Promise 的优势

async 函数是什么?
谈及异步回调函数的嵌套,总会让人感到烦躁,特别是当业务逻辑复杂,往往需要调用几次 ajax 才能拿到所有需要的数据。
从最早的回调函数,到 Promise 对象,再到 Generator 函数,每次都有所改进,但又让人觉得不彻底。它们都有额外的复杂性,都需要理解抽象的底层运行机制。所以,我们需要一种方法,更优雅地解决异步操作。于是,async函数出现了。
一句话解释:async 函数,就是 Generator 函数的语法糖。
它有以下几个特点:

建立在 promise 之上。所以,不能把它和回调函数搭配使用。但它会声明一个异步函数,并隐式地返回一个Promise。因此可以直接return变量,无需使用 Promise.resolve 进行转换。
和 promise 一样,是非阻塞的。但不用写 then 及其回调函数,这减少代码行数,也避免了代码嵌套。而且,所有异步调用,可以写在同一个代码块中,无需定义多余的中间变量。
它的最大价值在于,可以使异步代码,在形式上,更接近于同步代码。
它总是与 await 一起使用的。并且,await 只能在 async 函数体内。
await 是个运算符,用于组成表达式,它会阻塞后面的代码。如果等到的是 Promise 对象,则得到其 resolve 值。否则,会得到一个表达式的运算结果。

为何说 async 函数是语法糖
async 函数的实现,其实就是将 Generator 函数和自动执行器,包装在一个函数里。

async function fn(args) {
    // ...
}

// 等同于
function fn(args) {
    return spawn(function*() {
        // ...
    });
}

// spawn 函数就是自动执行器
function spawn(genF) {
    return new Promise(function(resolve, reject) {
        var gen = genF();
        function step(nextF) {
            try {
                var next = nextF();
            } catch(e) {
                return reject(e);
        }
        if(next.done) {
            return resolve(next.value);
        }
        Promise.resolve(next.value).then(function(v) {
            step(function() { return gen.next(v); });
        }, function(e) {
            step(function() { return gen.throw(e); });
        });
    }
    step(function() { return gen.next(undefined); });
  });
}

所以说,async 函数是 Generator 函数的语法糖。另外,它相对较新,属于 ES8 中的语法。但是转码器 Babel 已经支持,转码后就能使用。

async 相较于 Promise 的优势
1.相比于 Promise,它能更好地处理 then 链

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

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(n) {
    console.log(`step2 with ${n}`);
    return takeLongTime(n);
}

function step3(n) {
    console.log(`step3 with ${n}`);
    return takeLongTime(n);
}

现在用 Promise 方式来实现这三个步骤的处理。

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}`);
        });
}
doIt();
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900

如果用 async/await 来实现的话,会是这样:

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
}
doIt();

结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样。

2.中间值
现在把业务要求改一下,仍然是三个步骤,但每一个步骤都需要之前每个步骤的结果。Pomise的实现看着很晕,传递参数太过麻烦。

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => {
            return step2(time1, time2)
                .then(time3 => [time1, time2, time3]);
        })
        .then(times => {
            const [time1, time2, time3] = times;
            return step3(time1, time2, time3);
        })
        .then(result => {
            console.log(`result is ${result}`);
        });
}
doIt();

用 async/await 来写:

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time1, time2);
    const result = await step3(time1, time2, time3);
    console.log(`result is ${result}`);
}
doIt();

没有多余的中间值,更加优雅地实现了。
3.调试
相比于 Promise 更易于调试。
因为没有代码块,所以不能在一个返回的箭头函数中设置断点。如果你在一个 .then 代码块中使用调试器的步进(step-over)功能,调试器并不会进入后续的 .then 代码块,因为调试器只能跟踪同步代码的每一步。


现在,如果使用 async/await,你就不必再使用箭头函数。你可以对 await 语句执行步进操作,就好像他们都是普通的同步语句一样。

总结
每一个特性的出现,总有它的用途,而只有用了,才能更好地理解它。
JavaScript的异步编写方式,从 回调函数 到 Promise、Generator 再到 Async/Await。表面上只是写法的变化,但本质上则是语言层的一次次抽象。让我们可以用更简单的方式实现同样的功能,而不需要去考虑代码是如何执行的。
换句话说就是:异步编程的最高境界,就是根本不用关心它是不是异步。

原文地址:http://blog.51cto.com/13981400/2343049

时间: 2024-08-30 10:06:58

细说 async/await 相较于 Promise 的优势的相关文章

js async await 终极异步解决方案

既然有了promise 为什么还要有async await ? 当然是promise 也不是完美的异步解决方案,而 async await 的写法看起来更加简单且容易理解. 回顾 Promise Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值. Promise 对象是由关键字 new 及其构造函数来创建的.构造函数会,把一个叫做“处理器函数”(executor function)的函数作为它的参数.这个“处理器函数”接受两个函数resolve 和 reject 

JavaScript 的 Async\/Await 完胜 Promise 的六

参考:http://www.10tiao.com/html/558/201705/2650964601/1.html Node 现在从版本 7.6 开始就支持 async/await 了. 简介: Async/await 是一种编写异步代码的新方法.之前异步代码的方案是回调和 promise. Async/await 实际上是建立在 promise 的基础上.它不能与普通回调或者 node 回调一起用. Async/await 像 promise 一样,也是非阻塞的. Async/await 让

JavaScript异步编程——Async/Await vs Promise

兼容性 提醒一下各位,Node 现在从版本 7.6 开始就支持 async/await 了.而就在前几天,Node 8已经正式发布了,你可以放心地使用它. 如果你还没有试过它,这里有一堆带有示例的理由来说明为什么你应该马上采用它,并且再也不会回头. Async/await  对于那些从未听说过这个话题的人来说,如下是一个简单的介绍: Async/await 是一种编写异步代码的新方法.之前异步代码的方案是回调和 promise. Async/await 实际上是建立在 promise 的基础上.

重构:从Promise到Async/Await

摘要: 夸张点说,技术的发展与历史一样,顺之者昌,逆之者亡.JS开发者们,赶紧拥抱Async/Await吧! GitHub仓库: Fundebug/promise-asyncawait 早在半年多之前,我就在鼓吹Async/Await替代Promise的6个理由,似乎还招致了一些批评.然而,直到最近,我才真正开始进行代码重构,抛弃Promise,全面使用Async/Await.因为,Node 8终于LTS了! Async/Await真的比Promise好吗? 是的是的. 这些天,我大概重构了10

Async/Await替代Promise的理由

Async/Await简介 对于从未听说过async/await的朋友,下面是简介: async/await是写异步代码的新方式,以前的方法有回调函数和Promise. async/await是基于Promise实现的,它不能用于普通的回调函数. async/await与Promise一样,是非阻塞的. async/await使得异步代码看起来像同步代码,这正是它的魔力所在. Async/Await语法 示例中,getJSON函数返回一个promise,这个promise成功resolve时会返

callback vs async.js vs promise vs async / await

需求: A.依次读取 A|B|C 三个文件,如果有失败,则立即终止. B.同时读取 A|B|C 三个文件,如果有失败,则立即终止. 一.callback 需求A: let read = function (code) { if (code) { return true; } else { return false; } } let readFileA = function (callback) { if (read(1)) { return callback(null, "111");

promise/async/await

promise和async/await都是异步方案,promise是es6的新特性,而async/await是es7新出的特性.而对于async/await来说是基于promise的,他可以让我们更加优雅的写出代码,而替代then()的写法,例如: const f = () => { return new Promise((resolve, reject) => { setTimeout(() => { reject(234); }, 2000); }); }; const testAs

关于async/await、promise和setTimeout执行顺序

先来一道关于async/await.promise和setTimeout的执行顺序的题目: 1 async function async1() { 2 console.log('async1 start'); 3 await async2(); 4 console.log('asnyc1 end'); 5 } 6 async function async2() { 7 console.log('async2'); 8 } 9 console.log('script start'); 10 set

async await yield

问题:async 和yield有什么区别? 无奈只能用“书到用时方恨少”来解释这个问题了.其实也是自己从开始编程就接触的是nodejs中的async 以及await ,yield几乎.貌似好像都没使用过,至于它俩的区别,自己也就一知半解了,还希望看到这个问题的大神可以指教一二. 零零总总的总结一点: 1.ES6语法:async 与await搭配使用,不能拆开: 2.都是属于异步方案: 3.本质上:是解决异步编程怎么像同步编成那样写的: 4.yield :需要手动控制异步执行过程,调用.next(