JavaScript: Handling errors like Go Everyday Promise-like functions Converting to async/await Unified return interface with async/await

2025-06-11

JavaScript:像 Go 一样处理错误

类似 Promise 的日常功能

转换为async/await

统一返回接口与async/await

早在八月份,我就用巴西葡萄牙语写了一篇文章,解释如何使用async/await来隔离错误处理。

今天我将把它翻译成英文,但用不同的例子!


我很喜欢Go类似同步的方式处理副作用。我们来看看 Gonet/http包中的这个例子:

func main() {
  res, err := http.Get("http://example.com/")

  if err != nil {
    // handle `err`
  }

  // do something with `res`
}
Enter fullscreen mode Exit fullscreen mode

或者也许是这个os包:

func main() {
  file, err := os.Open("words.txt")

  if err != nil {
    // handle `err`
  }

  // do something with `file`
}
Enter fullscreen mode Exit fullscreen mode

除了实现细节之外,我想知道是否有办法用 JavaScript 编写这样的内容?

嗯,正如他们所说,有志者事竟成!😂

类似 Promise 的日常功能

如今,类似 Promise 的环境在我们之中很常见。

我们可以使用它来读取 Node.js 中的文件:

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

let read = util.promisify(fs.readFile);

function main() {
  read("./test.js", { encoding: "utf8" })
    .then(file => {
      // do something with `file`
    })
    .catch(err => {
      // handle `err`
    });
}

main();
Enter fullscreen mode Exit fullscreen mode

也许从 API 中获取一些数据:

let url = "https://dog.ceo/api/breeds/image/random";

function main() {
  fetch(url)
    .then(res => res.json())
    .then(res => {
      // do something with `res`
    })
    .catch(err => {
      // handle `err`
    });
}

main();
Enter fullscreen mode Exit fullscreen mode

由于生性懒惰,我们创建函数来隐藏一些样板,这样我们就可以在整个代码库中编写更少的代码:

let readFile = require("./readFile");

function main() {
  readFile("./test.js")
    .then(file => {
      // do something with `file`
    })
    .catch(err => {
      // handle `err`
    });
}

main();


// readFile.js
let util = require("util");
let fs = require("fs");

let read = util.promisify(fs.readFile);

module.exports = path => {
  return read(path, { encoding: "utf8" })
    .then(file => {
      return file;
    })
    .catch(err => {
      throw err;
    });
};
Enter fullscreen mode Exit fullscreen mode

和:

let api = require("./api");

function main() {
  api.getRandomDog()
    .then(res => {
      // do something with `res`
    })
    .catch(err => {
      // handle `err`
    });
}

main();


// api.js
let url = "https://dog.ceo/api/breeds/image/random";

let api = {};

api.getRandomDog = () => {
  return fetch(url)
    .then(res => res.json())
    .catch(err => {
      throw err;
    });
};

module.exports = api;
Enter fullscreen mode Exit fullscreen mode

尽管如此,这里还是有很多重复,在这段代码片段的两边.then都有。.catch

他们说async/await可以解决这个问题,那么...我们试试看吧?

转换为async/await

async让我们看看 Node.js 在/中的运行情况await

let readFile = require("./readFile");

async function main() {
  try {
    let res = await readFile("./test.js");
    // do something with `file`
  } catch (err) {
    // handle `err`
  }
}

main();


// readFile.js
let util = require("util");
let fs = require("fs");

let read = util.promisify(fs.readFile);

module.exports = async path => {
  try {
    let res = await read(path, { encoding: "utf8" });
    return res;
  } catch (err) {
    throw err;
  }
};
Enter fullscreen mode Exit fullscreen mode

我们怎样才能用它来带走我们的狗呢?

let api = require("./api");

async function main() {
  try {
    let res = await api.getRandomDog();
    // do something with `res`
  } catch (err) {
    // handle `err`
  }
}

main();

// api.js
let url = "https://dog.ceo/api/breeds/image/random";

let api = {};

api.getRandomDog = async () => {
  try {
    let res = await fetch(url);
    let json = await res.json();
    return json;
  } catch (err) {
    throw err;
  }
};

module.exports = api;
Enter fullscreen mode Exit fullscreen mode

呼……我觉得我们把一个问题改成了另一个问题。现在try...catch两个地方都有了。想想我们目前消费者/服务之间的接口,我们已经:

  1. 在我们的main()函数中,我们调用一个“服务”(readFileapi。
  2. 我们的“服务”功能返回一个Promise
  3. 当完成后,我们的服务将返回有效载荷
  4. 当被拒绝时,我们的服务会抛出错误

嗯……也许这就是问题所在!对于已完成和已拒绝的情况,我们消费者/服务之间的接口是不同的

刷新我们对顶部的Go示例的记忆:

 func main() {
  res, err := http.Get("http://example.com/")

  if err != nil {
    // handle `err`
  }

  // do something with `res`
}
Enter fullscreen mode Exit fullscreen mode

看来我们对已完成和已拒绝的情况都有相同的界面!

让我们用最后一个async/await示例来尝试一下!

统一返回接口与async/await

在我们的 Node.js 示例中:

let readFile = require("./readFile");

async function main() {
  let [err, file] = await readFile("./test.js");

  if (err) {
    // handle `err`
  }

  // do something with `file`
}

main();


// readFile.js
let util = require("util");
let fs = require("fs");

let read = util.promisify(fs.readFile);

module.exports = async path => {
  try {
    let res = await read(path, { encoding: "utf8" });
    return [null, res];
  } catch (err) {
    return [err, null]
  }
};
Enter fullscreen mode Exit fullscreen mode

我们的 Fetch API:

let api = require("./api");

async function main() {
  let [err, res] = await api.getRandomDog();

  if (err) {
    // handle `err`
  }

  // do something with `res`
}

main();

// api.js
let url = "https://dog.ceo/api/breeds/image/random";

let api = {};

api.getRandomDog = async () => {
  try {
    let res = await fetch(url);
    let json = await res.json();
    return [null, json];
  } catch (err) {
    return [err, null]
  }
};

module.exports = api;
Enter fullscreen mode Exit fullscreen mode

做得好!!🎉🎉🎉

这正是我们想要的!我们的main()函数看起来就像 Go 示例一样,现在我们已经将所有内容隔离到了try...catch“服务”函数中。

使用这种方法,您可以清理您的 Node.js 中间件/控制器和前端,比如说使用 React/Redux,清理redux-thunksredux-saga函数/生成器。

您还可以单独对这些“服务”功能进行单元测试,并确保它们返回预期的接口/数据。

鏂囩珷鏉ユ簮锛�https://dev.to/oieduardorabelo/javascript-handling-errors-like-go-3efk
PREV
软件工程的最佳资源
NEXT
使用 ChatGPT、Stable Diffusion、React 和 NodeJS 构建网站画廊🤯 TLDR;