Skip to content

9. 错误与异常

Image

JavaScript 并没有一个非常复杂的异常处理系统。不过,它确实提供了 [throw] 语句,允许你触发错误,同时也提供了 try/catch/finally 结构,允许你捕获这些错误。

9.1. 脚本 [excep-01]

在下面的脚本中,我们将以 [小时:分钟:秒:毫秒] 的格式显示当前日期。为此,我们将使用一个名为 [moment.js] 的 JavaScript 库。我们像往常一样,使用 [npm] 工具进行安装:

Image

脚本代码如下:


'use strict';
 
// package moment
import moment from 'moment';
 
...

要理解第 4 行中 [import] 语句的写法,我们可以查看 [moment] 模块的定义:

Image

  • [1-2] 中,我们跳转到了模块定义;
  • [3] 中,我们看到的是一个 TypeScript 文件,而非 JavaScript 文件。运行时,该 TypeScript 文件会被编译成 JavaScript 文件后才被使用;
  • [4] 中,我们搜索 [export] 语句(Ctrl-F);
  • [5] 中,该语句导出了 [moment] 对象。在 ES6 中,可以按以下方式导入它:

import moment from 'moment';

您可以使用任意名称来导入 [moment] 对象,例如:


import m from 'moment';

让我们回到脚本代码:


'use strict';
 
// package moment
import moment from 'moment';
 
// try / catch / finally principle
for (let i = 0; i < 10; i++) {
  // date - current time
  const now = Date.now();
  // format time to get milliseconds
  const time = moment(now).format("HH:mm:ss:SSS");
  // milliseconds
  const milli = Number(time.substr(time.length - 3));
  // display
  console.log("--------------------itération n° ", i, "à", time);
  try {
    // number varies according to time of day
    const nbre = milli % 2;
    if (nbre === 0) {
      // launch an error msg
      throw "erreur";
    }
    // if we've arrived here, there's been no mistake
    console.log("pas d'erreur");
  } catch (error) {
    // if we get here, it's because there's been a mistake
    console.log("erreur1=", error);
  } finally {
    // executed in all cases error or not
    console.log("finally")
  }
}

注释

  • 第 4 行:导入 [moment] 库;
  • 脚本循环执行10次(第7行)。每次循环迭代中,都会以 [小时:分钟:秒:毫秒] 的格式获取当前时间(第8–13行);
  • 如果毫秒数为偶数,则显示一条错误信息(第19–22行);
  • 此处的目的是理解 try / catch / finally 的工作原理

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\exceptions\excep-01.js"
--------------------itération n° 0 à 17:57:04:440
erreur1= erreur
finally
--------------------itération n° 1 à 17:57:04:447
pas d'erreur
finally
--------------------itération n° 2 à 17:57:04:448
erreur1= erreur
finally
--------------------itération n° 3 à 17:57:04:448
erreur1= erreur
finally
--------------------itération n° 4 à 17:57:04:448
erreur1= erreur
finally
--------------------itération n° 5 à 17:57:04:448
erreur1= erreur
finally
--------------------itération n° 6 à 17:57:04:448
erreur1= erreur
finally
--------------------itération n° 7 à 17:57:04:448
erreur1= erreur
finally
--------------------itération n° 8 à 17:57:04:449
pas d'erreur
finally
--------------------itération n° 9 à 17:57:04:449
pas d'erreur
finally

我们可以看到,无论是否发生错误,[finally] 子句都会被执行。

9.2. 脚本 [excep-02]

本脚本演示了 [throw] 语句可以抛出任何类型的数据,并且这些数据会被 [catch] 子句完全捕获。


'use strict';
 
// you can "throw" just about anything to signal an error
let i = 0;
console.log("--------------------essai n° ", i);
// launch a string
try {
  throw "msg d'erreur";
} catch (error) {
  // there has been a mistake
  console.log("erreur=[", error, "], type=", typeof (error));
}
// launch a table
i++;
console.log("--------------------essai n° ", i);
try {
  throw [1, 2, 3]
} catch (error) {
  // there has been a mistake
  console.log("erreur=[", error, "], type=", typeof (error));
}
// launch a literal object
i++;
console.log("--------------------essai n° ", i);
try {
  throw { nom: "hercule", pays: "grèce antique" }
} catch (error) {
  // there has been a mistake
  console.log("erreur=[", error, "], type=", typeof (error));
}
// lancer un type Error
i++;
console.log("--------------------essai n° ", i);
try {
  throw new Error("erreur de connexion au réseau");
} catch (error) {
  // there has been a mistake
  console.log("erreur=[", error, "], type=", typeof (error));
}
// lancer un type Error
i++;
console.log("--------------------essai n° ", i);
try {
  throw new Error("erreur de connexion au réseau");
} catch (error) {
  // there has been an error - the message is in [error.message]
  console.log("erreur.message=[", error.message, "], type(error)=", typeof (error));
}

注释

  • 第 35、44 行:[Error] 是一个 JavaScript 类,其构造函数接受一条错误消息作为可选的第一个参数。该消息可通过 [Error.message] 属性获取(第 47 行);
  • 除了 [Error] 之外,还有其他类可以触发错误:[EvalError, InternalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError];

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\exceptions\excep-02.js"
--------------------essai n° 0
erreur=[ msg d'erreur ], type= string
--------------------essai n° 1
erreur=[ [ 1, 2, 3 ] ], type= object
--------------------essai n° 2
erreur=[ { nom: 'hercule', pays: 'grèce antique' } ], type= object
--------------------essai n° 3
erreur=[ Error: erreur de connexion au réseau
at Object.<anonymous> (c:\Data\st-2019\dev\es6\javascript\exceptions\excep-02.js:35:9)
at Object.<anonymous> (c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:251206)
at c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:245054
at Generator.next (<anonymous>)
at bl (c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:245412)
at kl (c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:247659)
at Object.u (c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:287740)
at Object.o (c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:287137)
at Object.<anonymous> (c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:284879)
at Object.apply (c:\Temp\19-09-01\javascript\node_modules\esm\esm.js:1:199341) ], type= object
--------------------essai n° 4
erreur.message=[ erreur de connexion au réseau ], type(error)= object

9.3. 脚本 [excep-03]

此脚本演示了在 [catch] 块内,可以区分由 [catch] 捕获的 [Error] 实例的类型:


'use strict';
 
// package moment
import moment from 'moment';
 
// differentiate the Error instance received in a [catch]
for (let i = 0; i < 10; i++) {
  // date - current time
  const now = Date.now();
  // format time to get milliseconds
  const time = moment(now).format("HH:mm:ss:SSS");
  // milliseconds
  const milli = Number(time.substr(time.length - 3));
  console.log("--------------------itération n° ", i);
  try {
    // nbre [0, 1, 2]
    const nbre = milli % 3;
    switch (nbre) {
      case 0:
        throw new ReferenceError("erreur 1");
      case 1:
        throw new RangeError("erreur 2");
      default:
        throw new EvalError("erreur 3");
    }
  } catch (error) {
    // there has been a mistake
    if (error instanceof ReferenceError) {
      console.log("ReferenceError :", error.message);
    } else {
      if (error instanceof RangeError) {
        console.log("RangeError :", error.message);
      }
      else {
        if (error instanceof EvalError) {
          console.log("EvalError :", error.message);
        }
      }
    }
  }
}

执行


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe -r esm "c:\Data\st-2019\dev\es6\javascript\exceptions\excep-03.js"
--------------------itération n° 0
ReferenceError : erreur 1
--------------------itération n° 1
RangeError : erreur 2
--------------------itération n° 2
RangeError : erreur 2
--------------------itération n° 3
RangeError : erreur 2
--------------------itération n° 4
RangeError : erreur 2
--------------------itération n° 5
RangeError : erreur 2
--------------------itération n° 6
EvalError : erreur 3
--------------------itération n° 7
EvalError : erreur 3
--------------------itération n° 8
EvalError : erreur 3
--------------------itération n° 9
EvalError : erreur 3