node Promise 转换

如果你曾经使用 Javascript,你必须有经验的回调。Javascript 以其内置的异步哲学而闻名。从标准内置模块到其他框架和库,回调无处不在。这就是在 Javascript 中完成异步编程。但是回调有一个黑暗的一面。这叫 Callback Hells。

回调地狱的解决方案是 Promises。而不是通过回调同步返回值或传递结果,我们可以返回一个 Promise,我们将来会返回一些值或错误。 有许多像好的库如 Bluebird 和 Q 可以用来处理 Promise。但是内置的模块和很多其他库不能使用 Promises。这些库能够将传统的回调方法转换为 Promise,在 Node v8 中我们现在可以使用 util.promisify 来处理回调方法。根据 Node.js 的文档: util.promisify(original)

  • original
  • Returns:
const util = require("util");
const fs = require("fs");

const stat = util.promisify(fs.stat);
stat(".")
  .then((stats) => {
    // Do something with `stats`
  })
  .catch((error) => {
    // Handle the error.
  });

或者;

const util = require("util");
const fs = require("fs");

const stat = util.promisify(fs.stat);

async function callStat() {
  const stats = await stat(".");
  console.log(`This directory is owned by ${stats.uid}`);
}

看传统的例子:

const fs = require("fs");
fs.readFile("./index.js", "utf8", (err, text) => {
  if (err) {
    console.log("Error", err);
  } else {
    console.log(text);
  }
});

现在这个例子可以用 Promises 写成如下:

const fs = require("fs");
const util = require("util");
const readFile = util.promisify(fs.readFile);
readFile("./index.js", "utf8")
  .then((text) => {
    console.log(text);
  })
  .catch((err) => {
    console.log("Error", err);
  });

在这里我们习惯于 util.promisify 将 fs.readFile 转换为基于 promise 的方法。现在,而不是采取回调,readFile 方法作为一个 pormise。promise 有两个方法,then 和 catch。then 如果函数调用成功,则用于获取结果。而 catch 用于捕获错误。Promise 的优点在于,我们可以使用异步的链式写法而不会陷入回调地狱

结合 async 和 await 关键字,promise 可以更容易处理。链式太长的话也会使程序难于阅读。async 和 await 使它看起来更清洁。以下是 Async&Await 的上面的例子:

const fs = require("fs");
const util = require("util");
const readFile = util.promisify(fs.readFile);
(async function () {
  try {
    const text = await readFile("./index.js", "utf8");
    console.log(text);
  } catch (err) {
    console.log("Error", err);
  }
})();

异步函数改为回调

回调是异步执行的,并且具有有限的堆栈跟踪。如果回调抛出,则进程将发出一个’uncaughtException’ 事件,如果未处理则将退出

util.callbackify(original)
original <Function> An async function
Returns: <Function> a callback style function


const util = require('util');

async function fn() {
  return 'hello world';
}
const callbackFunction = util.callbackify(fn);

callbackFunction((err, ret) => {
  if (err) throw err;
  console.log(ret);
});