Javascript Promise 对象和 async 函数

ES2015 引入了 Promise 接口,ES2017 引入了 async 函数语法。Promise 是为了代替回调函数式的写法;async 函数则为了代替 Promise 式的写法。

使用回调函数的一个弊端就是会出现“邪恶金字塔(Pyramid of Doom)”。

let fs = require('fs');
fs.readFile('sample01.txt', 'utf8', function (err, data1) {
    fs.readFile('sample02.txt', 'utf8', function (err,data2) {
        fs.readFile('sample03.txt', 'utf8', function (err, data3) {
            fs.readFile('sample04.txt', 'utf8', function (err, data4) {
                // ...
            });
        });
    });
});

用 Promise 改写就是

let fs = require('fs');

let readFile = function (filename) {
    return new Promise(function (resolve, reject) {
        fs.readFile(filename, 'utf8', function (err, data) {
            if (error) return reject(error);
            resolve(data);
        })
    });
}

readFile('sample01.txt')
    .then(function (data1) {
        return readFile('sample02.txt')
    })
    .then(function (data2) {
        return readFile('sample03.txt')
    })
    .then(function (data3) {
        return readFile('sample04.txt')
    })
    .then(function (data4) {
        console.log('All done!');
    })

Promise 的 then 方法总是返回一个新的 Promise 对象,以便使用垂直的链式写法。当前一个 then 方法中返回的 一个 Promise 对象时,紧随其后的 then 方法相当于是它的 then 方法;当前一个 then 方法中返回的 不是 一个 Promise 对象时,这个返回值会直接作为参数传递给紧随其后的 then 方法中。

async 函数与普通函数相比,返回值总是一个 Promise 对象。await 只能用在 async 函数中,它在执行过程中,总把紧跟在后面的值转换为 Promise 对象,然后将传递给该 Promise 对象 then 方法的参数直接返回。

所以,上面的例子使用 async 函数改写如下:

let asyncReadFile = async function () {
    let data1 = await readFile('sample01.txt');
    let data2 = await readFile('sample02.txt');
    let data3 = await readFile('sample03.txt');
    let data4 = await readFile('sample04.txt');
    let data5 = await readFile('sample05.txt');

    return 'All done!'
}

Promise 写法那一串 then 消失不见啦!代码更清晰,更像是“同步代码”的写法。

无论 await 后面的请求是异步还是同步的,后一个 readFile 总是等到前一个 readFile 执行完毕后才会执行。一句话,async 函数可以将多个异步操作聚合成一个异步操作,内部的即使有异步操作,但也表现的像同步操作,因为代码总是自上而下同步执行的。

let res = await promise;

// 相当于
promise
    .then(function (res) {
        // ...
    });

await 后面常跟的是一个返回值是 Promise 对象的表达式;当 await 后面不是跟 Promise 对象的时候,会将其转化为 resolved 状态的 Promise 对象立即返回。

async function func() {
    return await { username: 'zhangbao' };
}

// 等同于
async function func() {
    return Promise.resolve({ username: 'zhangbao' });
}

func()
    .then(res => {
    console.log(res);
    });

// 打印结果:
// Object {
//   username: "zhangbao"
// }

asyns 函数的执行不会阻塞后面的代码执行:

async function func() {
    return new Promise(function (resolve, reject) {
        setTimeout(() => {
            resolve('resolved');
        }, 1000);
    });
}

func()
    .then(res => {
    console.log(res);
    });

console.log('end');

// 打印结果:
// "end"
// "resolved"

参考链接:

评论数量: 0

0
点赞
137
浏览
0
评论

贡献 16