我最近一直在想,并且它发生在我,当谈到一个良好的错误处理在JavaScript,它是不相关的哪个框架,你使用,Angular在别的东西。我最近为一个AngularJS项目写了一个这样的错误处理程序,但我做了一个方式,它可以在任何框架中使用。
这里是完整的代码。您可以直接使用它,或修改为您的需要…
/*
Factory errorFact is to simplify error handling and reporting in other objects.
It supports detailed error output as a text string and into the browser's console.
Usage example:
A function that supports return of an error object would have the following declaration
as its very first line:
var e = errorFact.create("objectName.funcName", arguments);
- in this declaration we specify the full object + method name as the first string parameter,
- and as the second parameter we pass javascript's reserved variable called arguments, which
provides reference to all of the function's parameters for logging.
When an error occurs, the function would return:
return e.error("Error description text");
- this line will create and return a complete error context.
When a function that supports return of an error object makes a call into another
function that also supports the error context, then it can return the nested error
result by passing the embedded error to the current error object instead of the error
text.
Example:
var e = errorFact.create("objectName.funcName", arguments);
var data = callAnotherFunc(...); // calling a function that support an error object;
if(data.isError){ // If an error was triggered;
return e.error(data); // return that error from the current context;
}
The top-level code that calls an error-returning function would do verification
and if an error occurred, log all its details into console (typically).
Example:
var data = getData(...);
if(data.isError){
data.log(); // Output all the error details into the browser's console;
}
*/
"use strict";
app.factory("errorFact", function(){
return {
// creates a new error context;
create: function(method, args){
var result = {
// initiates and returns the error context;
error: function(msg){
this.info.isError = true;
if(msg.isError){
this.info.details.caller = msg;
}else{
this.info.details.msg = msg;
}
return this.info;
},
info:
{
isError: false,
details: {},
log: function(){
if(this.isError){
console.error(this.format());
}
},
// formats complete error details into a text string;
format: function(){
if(this.details.caller){
var txt = this.details.caller.format();
txt += "\nCALLER: " + this.details.method + "(" + this.formatArguments() + ")";
return txt;
}
if(this.details.method){
return "Error calling " + this.details.method + "(" + this.formatArguments() + "): " + this.details.msg;
}else{
return this.details.msg;
}
return "";
},
// formats function argument details into a text string;
formatArguments: function(){
if(!this.details.args){
return "";
}
var params = "";
for(var i = 0;i < this.details.args.length;i ++){
if(params.length > 0){
params += ",";
}
var p = this.details.args[i];
if(p === undefined){
params += "undefined";
}else{
if(p === null){
params += "null";
}else{
if(typeof(p) == "object"){
params += "Object";
}else{
params += p;
}
}
}
}
return params;
}
}
};
if(method){
result.info.details.method = method;
}
if(args){
result.info.details.args = args;
}
return result;
}
}
});
下面是一个显示如何使用它的工厂:
"use strict";
app.factory('moduleFact', ['errorFact', function(errorFact){
return {
// Locates existing module and expands its key Id references
// into corresponding object references:
// - If 'hintGroupId' is present, property 'hints' is added from
// the corresponding hint group.
// - If 'repModules' is present, properties 'question' and 'refs'
// are added.
// On success, return the expanded module object.
// On failure, returns an error object.
//
// NOTE: Currently supports only the first value in repModules.
expandModule: function(moduleData, moduleId){
var e = errorFact.create("moduleFact.expandModule", arguments);
if(!moduleData || !moduleData.modules || !moduleId){
return e.error("Invalid parameters passed");
}
var mod = this.findModule(moduleData, moduleId);
if(mod.isError){
return e.error(mod);
}
var src = mod;
if(mod.repModules){
var repId = mod.repModules[0];
if(!repId){
return e.error("Invalid repModules encountered");
}
///
// temporary check to throw a warning:
if(mod.repModules.length > 1){
console.warn("Multiple values in property repModules: " + JSON.stringify(mod.repModules) +
", which is not supported yet (only the first value is used)");
}
///
src = this.findModule(moduleData, repId);
if(src.isError){
return e.error(src);
}
}
if(src.question){
mod.question = src.question;
}else{
return e.error("Question not specified");
}
if(src.refs){
mod.refs = src.refs;
}
if(src.hintGroupId){
var hg = this.findHintGroup(moduleData, src.hintGroupId);
if(hg.isError){
return e.error(hg);
}
mod.hints = hg.hints;
}
return mod; // needed extra: expand attribute repModules
},
// Expands all the modules and returns the data;
expandAllModules: function(moduleData){
var e = errorFact.create("moduleFact.expandAllModules", arguments);
if(!moduleData || !moduleData.modules){
return e.error("Invalid parameters passed");
}
for(var i = 0;i < moduleData.modules.length;i ++){
var result = this.expandModule(moduleData, moduleData.modules[i].id);
if(result.isError){
return e.error(result);
}
}
return moduleData;
},
// Locates and returns module by its Id;
findModule: function(moduleData, moduleId){
var e = errorFact.create("moduleFact.findModule", arguments);
if(!moduleData || !moduleData.modules || !moduleId){
return e.error("Invalid parameters passed");
}
for(var i = 0;i < moduleData.modules.length;i ++){
if(moduleData.modules[i].id == moduleId){
return moduleData.modules[i];
}
}
return e.error("Module with Id = " + moduleId + " not found");
},
// Locates and returns Hint Group by its Id;
findHintGroup: function(moduleData, hintGroupId){
var e = errorFact.create("moduleFact.findHintGroup", arguments);
if(!moduleData || !moduleData.hintGroups || !hintGroupId){
return e.error("Invalid parameters passed");
}
for(var i = 0;i < moduleData.hintGroups.length;i ++){
if(moduleData.hintGroups[i].id == hintGroupId){
return moduleData.hintGroups[i];
}
}
return e.error("Hint Group with Id = " + hintGroupId + " not found");
}
}
}]);
所以,当你有这样的工厂,你的高级代码,如在控制器中只会记录任何问题,如下面的例子所示:
"use strict";
app.controller('standardsCtrl', ['$scope', 'moduleFact', function($scope, moduleFact){
var data = ...//getting data;
var mod = moduleFact.expandAllModules(data);
if(mod.isError){
mod.log(); // log all error details into the console;
}else{
// use the data
}
});
}]);