对JavaScript中的异步函数举行非常处置惩罚及测试

翻译:猖獗的手艺宅

原文:
https://www.valentinog.com/bl…

本文首发微信民众号:jingchengyideng
迎接关注,天天都给你推送新颖的前端手艺文章

可以在 Javascript 的异步函数中抛出毛病吗?

这个话题已被重复提起过几百次,不过此次让我们从TDD(Test-Driven Development)的角度来回复它。

假如你能不在Stackoverflow上搜刮就可以回复这个题目,会给我留下深入的印象。

假如不能的话也可以很酷。 继承往下读,你就可以学到!

你将学到什么

经由过程背面的内容你将学到:

  • 怎样从 Javascript 的异步函数中抛出毛病
  • 怎样运用 Jest 测试来自异步函数的非常

请求

要继承往下读你应当:

  • 对 Javascript 和 ES6 有基础的相识
  • 装置 Node.Js 和 Jest

怎样从 Javascript 的通例函数中抛出毛病

运用非常而不是返回码(洁净代码)

抛出毛病是处置惩罚未知的最好要领。

一样的划定规矩适用于种种当代言语:Java、Javascript、Python、Ruby。

你可以从函数中抛出毛病,可以参照以下示例:

function upperCase(name) {
  if (typeof name !== "string") {
    throw TypeError("name must be a string");
  }
  return name.toUpperCase();
}
module.exports = upperCase;

这是对它的测试(运用Jest):

"use strict";
const assert = require("assert");
const upperCase = require("../function");
describe("upperCase function", () => {
  test("it throws when name is not provided", () => {
    assert.throws(() => upperCase());
  });
  test("it throws when name is not a string", () => {
    assert.throws(() => upperCase(9));
  });
});

也可以从 ES6 的类中抛出毛病。在 Javascript 中编写类时,我老是在组织函数中输入不测值。下面是一个例子:

class Person {
  constructor(name) {
    if (typeof name !== "string") {
      throw TypeError("name must be a string");
    }
    this.name = name;
  }
  // some method here
}
module.exports = Person;

以下是该类的测试:

"use strict";
const assert = require("assert");
const Person = require("../index");
describe("Person class", () => {
  test("it throws when name is not provided", () => {
    assert.throws(() => new Person());
  });
  test("it throws when name is not a string", () => {
    assert.throws(() => new Person(9));
  });
});

测试确切经由过程了:

PASS  test/index.test.js
 Person class
   ✓ it throws when name is not provided (1ms)
   ✓ it throws when name is not a string

部署的明明白白!

所以不管非常是从通例函数照样从类组织函数(或从要领)抛出的,统统都邑根据预期事情。

然则假如我想从异步函数中抛出毛病怎样办?

我可以在测试中运用assert.throws吗?

列位看官请上眼!

测试非常

既然都看到这里了,所以你应当晓得什么是 Javascript 的异步函数,对吗?先看一段代码:

class Person {
  constructor(name) {
    if (typeof name !== "string") {
      throw TypeError("name must be a string");
    }
    this.name = name;
  }
  // some method here
}
module.exports = Person;

假定你要增加异步要领来猎取有关该人的数据。这类要领须要一个网址。假如url不是字符串,就要像上一个例子中那样抛出毛病。

先来修正一下这个类:

class Person {
  constructor(name) {
    if (typeof name !== "string") {
      throw TypeError("name must be a string");
    }
    this.name = name;
  }
  async getData(url) {
    if (typeof url !== "string") {
      throw TypeError("url must be a string");
    }
    // const response = await fetch(url)
    // do stuff
  }
}
module.exports = Person;

假如我运转代码会怎样?尝尝吧:

const Person = require("../index");
const valentinogagliardi = new Person("valentinogagliardi");
valentinogagliardi.getData();

结果是如许

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: name must be a string
DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

果然不出所料,异步要领返回了一个Promise rejection,从严厉意义上来说,并没有抛出什么东西。毛病被包含在了Promise rejection中。

换句话说,我不能运用 assert.throws 来测试它。

让我们经由过程测试来考证一下:

"use strict";
const assert = require("assert");
const Person = require("../index");
describe("Person methods", () => {
  test("it throws when url is not a string", () => {
    const valentinogagliardi = new Person("valentinogagliardi");
    assert.throws(() => valentinogagliardi.getData());
  });
});

测试失利了!

FAIL  test/index.test.js
  Person methods › it throws when url is not a string
   assert.throws(function)
   Expected the function to throw an error.
   But it didn't throw anything.
   Message:
     Missing expected exception.

有无悟出点什么?

看把你能的,来抓我啊

从严厉意义上讲异步函数和异步要领不会抛出毛病。异步函数和异步要领老是返回一个Promise,不管它已完成照样被谢绝,你必需附上 then() 和 catch(),不管怎样。(或许将要领包装在try/catch中)。被谢绝的Promise将会在客栈中流传,除非你捉住(catch)它

至于测试代码,应当如许写:

"use strict";
const assert = require("assert");
const Person = require("../index");
describe("Person methods", () => {
  test("it rejects when url is not a string", async () => {
    expect.assertions(1);
    const valentinogagliardi = new Person("valentinogagliardi");
    await expect(valentinogagliardi.getData()).rejects.toEqual(
      TypeError("url must be a string")
    );
  });
});

我们测试的不能是一般的非常,而是带有TypeError的rejects。

如今测试经由过程了:

PASS  test/index.test.js
 Person methods
   ✓ it rejects when url is not a string

那代码该怎样写呢?为了可以捕捉毛病,你应当如许重构:

const Person = require("../index");
const valentinogagliardi = new Person("valentinogagliardi");
valentinogagliardi
  .getData()
  .then(res => res)
  .catch(err => console.error(err));

如今非常将会出如今掌握台中:

TypeError: url must be a string
    at Person.getData (/home/valentino/Documenti/articles-and-broadcasts/throw-from-async-functions-2018-04-02/index.js:12:13)
    at Object.<anonymous> (/home/valentino/Documenti/articles-and-broadcasts/throw-from-async-functions-2018-04-02/index.js:22:4)
    // ...

假如你想要更多的try/catch.,有一件主要的事须要注重。

下面的代码不会捕捉毛病:

const Person = require("../index");
async function whatever() {
  try {
    const valentinogagliardi = new Person("valentinogagliardi");
    await valentinogagliardi.getData();
    // do stuff with the eventual result and return something
  } catch (error) {
    throw Error(error);
  }
}
whatever();

记着:被谢绝的Promise会在客栈中流传,除非你捉住(catch)它。

要在 try/catch 中准确捕捉毛病,可以像如许重构:

async function whatever() {
  try {
    const valentinogagliardi = new Person("valentinogagliardi");
    await valentinogagliardi.getData();
    // do stuff with the eventual result and return something
  } catch (error) {
    throw Error(error);
  }
}
whatever().catch(err => console.error(err));

这就是它的事情道理。

总结

末了总结一下:

从异步函数抛出的毛病不会是“一般的非常”

异步函数和异步要领老是返回一个Promise,不管是已处理照样被谢绝。

要阻拦异步函数中的非常,必需运用catch()

以下是在Jest中测试非常的划定规矩:

  • 运用 assert.throws 来测试一般函数和要领中的非常
  • 运用 expect + rejects 来测试异步函数和异步要领中的非常

假如你对怎样运用 Jest 测试 Koa 2 感兴趣,请检察运用Jest和Supertest举行测试的简绍这篇文章。

谢谢浏览!

本文首发微信民众号:jingchengyideng

《对JavaScript中的异步函数举行非常处置惩罚及测试》
迎接扫描二维码关注民众号,天天都给你推送新颖的前端手艺文章

    原文作者:疯狂的技术宅
    原文地址: https://segmentfault.com/a/1190000018010005
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞