Promisification,把回调异步变为 Promise 链 --<Javascript 学习笔记 10>
Lemon1x 27 0

Javascript 学习笔记 10

这期没有用疑问句当作标题,因为我盯着屏幕看了两个小时才看懂这个东西,实在没心情疑问了。

Promisification 是把回调异步变为 Promise 链的函数,这个转换的过程叫做 Promisify 。

早期 JS 还没有 Promise 的时候,人们采用 回调 (Callback) 的方式来进行异步操作,来实现异步中同步、同步中异步,所以你可以看见很多老 API 仍然在使用,比如 Node.js 。

但是这样容易导致回调地狱,所以 ECMAScript 才发布了个 Promise ,但是你有没有想过把回调异步变为 Promise 链呢?虽然 Node.js 较新版本中有 Promisify 相关的函数,但是这里我们要自己实现。

这次我们转换的例子为 Node.js 中的 fs.readFile 函数,它便是采用了回调异步的 API 之一,它的语法如下:

/* 语法 */
fs.readFile(文件地址, callback(err, result));

/* 实例 */
fs.readFile('./test.txt', (err, result) => {
    if (err) throw new Error(err)
    console.log(result);
});

我们接下来要把它变成这样:

fs.readFile('./test.txt')
    .then(console.log, console.error);

废话不多说,直接开整:

var fs = require('fs');

function promisify(func) { // (*)
    return function (...args) { // (**)

        return new Promise((resolve, reject) => {

            function callback(err, result) { // (***)
                if (err) {
                    reject(err);
                } else {
                    resolve(result);
                }
            }

            args.push(callback); // (+)

            func(...args); // (-)
        });

    };
}

const read = promisify(fs.readFile);

read('./Async/catch.js') // 这个是我的环境下的一个文件,不用在意这个
    .then(console.log, console.error);

看起来很费解对吧,我们慢慢讲解,我把 Label 都写在了上述代码的注释中 (* - + 标记),大家一一对应就可以了。

  • ( * )

    传入一个回调函数,实现类似装饰器的功能

  • ( ** )

    ...args 包含了 readFile 的两个参数,至于为什么写成这样,后面会用到

  • ( *** )

    这个函数是对应 readFile 的第二个回调函数

  • ( + )

    把回调函数塞进 args 里,这样就自动传入了回调函数,你只需要写文件地址就可以了。这时你也许会奇怪, err 和 result 谁来传入呢?我当时也卡在了这里,实际上你把回调函数带入 readFile 就知道了,这俩参数不需要你传入,是 Node.js 自动给你传入的

  • ( - )

    传入文件地址和回调函数,也就是调用了 readFile

所以我换个写法没准你就懂了:

var fs = require('fs');

function promisify(func) {
    return function (file) {

        return new Promise((resolve, reject) => {

            func(file, (err, result) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(result);
                }
            });

        });

    };
}

const read = promisify(fs.readFile);

read('./Async/catch.js')
    .then(console.log, console.error);

行了,我觉得我讲的够清楚了,大家应该都能看懂,看不懂再来找我。

评论区

索引目录