Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node.js v8.0.0 新增方法 promisify #10

Open
sunhengzhe opened this issue Sep 17, 2017 · 1 comment
Open

Node.js v8.0.0 新增方法 promisify #10

sunhengzhe opened this issue Sep 17, 2017 · 1 comment
Labels

Comments

@sunhengzhe
Copy link
Member

sunhengzhe commented Sep 17, 2017

promisifyutil 模块下新增的方法,该方法接收一个传统的使用 callback 风格 的函数,并返回该函数返回 promise 的版本。查看官方文档

基本用法

传统的使用 callback 风格的函数诸如 fs.stat,接收若干参数,并且最后一个参数为 callback,该 callback 第一个参数总是 err。如下面的 sleep 函数:

function sleep(timestamp, callback) {
    setTimeout(function () {
        callback(null, 'done');
    }, timestamp);
}

// callback style
sleep(3000, (err, value) => {
    if (err) {
        return console.log('err', err);
    }

    console.log(value);
});

而使用 promisify 方法,可以生成一个返回 promise 的 sleep 函数:

const { promisify } = require('util');

function sleep(timestamp, callback) {
    setTimeout(function () {
        callback(null, 'done');
    }, timestamp);
}

const promisified = promisify(sleep);

promisified(3000).then(value => {
    console.log(value);
}).catch(err => {
    console.log('err:', err);
});

所以,理所当然地也能使用 async/await 写法:

async function main () {
    try {
        await promisified(3000);
    } catch (err) {
        console.log('err:', err);
    }
}

main();

callback 接收两个以上参数时

上面的 callback 除了 err 只有一个参数 "done",所以直接作为 promise 的 value 返回了。而以下函数的 callback 接收两个以上参数,比如 dns.lookup 的参数为 err、address、family。

  • child_process.exec
  • child_process.execFile
  • dns.lookup
  • dns.lookupService
  • fs.read
  • fs.write

此时 promisify 返回的 promise resolve 时将把除 err 外的参数整合到一个对象中作为 value。

const { promisify } = require('util');
const dns = require('dns');

const lookupAsync = promisify(dns.lookup);

lookupAsync('nodejs.org')
    .then(obj => console.log(obj));
    // { address: '104.20.22.46', family: 4 }

自定义 promisify 版本

Node.js 内置的函数 promisify 会整合参数,但自定义的 original 函数不符合 callback 风格怎么办?如当上面的 sleep 函数的 callback 接收多个参数的时候。那么可以自行指定 promisify 版本。只需要将自定义的 promisify 版本赋值给 original 函数的 util.promisify.custom symbol 属性上。

const { promisify } = require('util');

function sleep(timestamp, callback) {
    setTimeout(function () {
        callback(null, 'done', 'done2');
    }, timestamp);
}

function asyncSleep(timestamp) {
    return new Promise((resolve, reject) => {
        setTimeout(function () {
            resolve({
                arg1: 'done',
                arg2: 'done2',
            });
        }, timestamp);
    });
}

// 指定 promisify 版本
sleep[promisify.custom] = asyncSleep;

const promisified = promisify(sleep);

console.log(promisified === asyncSleep); // true

promisified(3000).then(console.log).catch(console.log);

最后

那么问题来了,如果让你实现一个 promisify 函数,你要如何实现?Node.js 的实现在 这里

@sunhengzhe
Copy link
Member Author

没奖竞猜:为什么内置函数可以把参数整合到一起呢?能用同样的方法让自定义函数也整合到一起吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant