当前位置: 移动技术网 > IT编程>网页制作>CSS > 怎样针对JavaScript中的异步函数进行异常处理及测试

怎样针对JavaScript中的异步函数进行异常处理及测试

2019年02月03日  | 移动技术网IT编程  | 我要评论

钟继华新浪博客,荷花资料,张筱雨 图

可以在 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. (/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));

这就是它的工作原理。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网