NodeJS的核心模組們一直以來都是以callback的形式來表現非同步行為,而callback會引起一個十分嚴重的callback hell問題。所幸在ES6時有了Promise的實作,大家將他視為是callback hell的一個解決之道,不過NodeJS可能礙於歷史因素,或者兼容性問題,並沒有將核心模組重新實作為Promise的形式,因此有了許多將Node核心模組轉換為Promise的方法,我們稱為Promisify,而在NodeJS 8.0.0的時候也有官方實作的Promisify方法可以使用。這篇介紹3個常見的方法,來達成Promisify的目的。

第一個介紹的方法是bluebird模組,bluebird是十分著名的Promise實作庫,提供的功能十分完整,它有兩種promisify方法一個是promisify對單個想要promisify化的函式進行promisify,而promisifyAll則可以一次對整個模組包進行promisify,使用起來超方便。

bluebird.promisify

    
const Promise = require('bluebird');                        // 引入bluebird模組
const fs = require('fs');

const fsStatePromise = Promise.promisify(fs.stat);          // 將我們想要promisify的node方法傳入Promise.promisify中

fsStatePromise('./app.js').then(data => console.log(data)); // fsStatePromise即是fs.stat的Promise版本

bluebird.promisifyAll

promisifyAll可以一次將模組全都promisify,但是不是取代掉原本的核心模組,而是加入不同名稱的新方法,預設會加入async的後綴。

例如: readFile就會變成readFileAsync

這個行為是可以改的,我個人更喜歡讓後綴是Promise,有利於增加識別度,而更改的方式就是在promisifyAll的第二個變數傳入suffix填入想要變更的後綴名稱。

    
const Promise = require('bluebird');                        // 引入bluebird模組
const fs = Promise.promisifyAll(require('fs'), {            // 將fs模組進行promisify
    suffix: 'Promise'                                       // promisify化後的方法名稱加上Promise的後綴
});

fs.readFilePromise('./app.js', 'utf-8').then(data => console.log(data))

NodeJS的util.promisify模組

這是在NodeJS 8.0.0版本以上官方實作的功能,我們可以將想要Promisify化的方法傳入util.promisify即可。

    
const promisify = require('util').promisify;    // 引入util模組中的promisify方法
const fs = require('fs');

const fsStatePromise = promisify(fs.stat);      // 將我們想要promisify的node方法傳入promisify中

fsStatePromise('app.js')
  .then((status) => console.log(status));       // fsStatePromise即是fs.stat的Promise版本

Reference:
1. bluebird - promisify
2. bluebird - promisifyall
3. Node util.promisify