2009-04-16 43 views
3

我來自Java,C#等領域。我正在爲我的Web應用程序開發javascript報表引擎。我正在使用jQuery,AJAX等。我很難按照我認爲他們應該做的方式工作 - 例如,我已經去了看起來太麻煩的事情,以確保在進行AJAX調用時,我的回調已經訪問對象的成員。這些回調函數不需要那麼複雜,是嗎?我知道我一定在做錯事。請指出我可以做得更好 - 讓我知道,如果提供的片段太多/太少/太可怕,不能看。如何讓這個javascript更易於閱讀,維護和理解OO背景?

我想要做的事:

  • 在頁面加載,我有一個選擇完全用戶。
  • 我創建報告(現在爲1)並將它們添加到選擇框中。
  • 當用戶和報告都被選中時,我運行報告。
  • 該報告涉及製作一系列電話 - 獲得練習系列,聯賽和錦標賽 - 對於每個聯賽和錦標賽,它將獲得所有這些系列賽,然後爲每個系列賽奪取所有比賽。
  • 它維護一個處於活動狀態的呼叫的計數器,當他們全部完成時,報告就會運行並顯示給用戶。

代碼:

//Initializes the handlers and reports 
function loadUI() { 
    loadReports(); 
    $("#userSelect").change(updateRunButton); 
    $("#runReport").click(runReport); 
    updateRunButton(); 
    return; 
    $("#userSelect").change(loadUserGames); 
    var user = $("#userSelect").val(); 
    if(user) { 
     getUserGames(user); 
    } 
} 

//Creates reports and adds them to the select 
function loadReports() { 
    var reportSelect = $("#reportSelect"); 
    var report = new SpareReport(); 
    engine.reports[report.name] = report; 
    reportSelect.append($("<option/>").text(report.name)); 

    reportSelect.change(updateRunButton); 
} 

//The class that represents the 1 report we can run right now. 
function SpareReport() { 
    this.name = "Spare Percentages"; 
    this.activate = function() { 

    }; 

    this.canRun = function() { 
     return true; 
    }; 

    //Collects the data for the report. Initializes/resets the class variables, 
    //and initiates calls to retrieve all user practices, leagues, and tournaments. 
    this.run = function() { 
     var rC = $("#rC"); 
     var user = engine.currentUser(); 
     rC.html("<img src='/img/loading.gif' alt='Loading...'/> <span id='reportProgress'>Loading games...</span>"); 
     this.pendingOperations = 3; 
     this.games = []; 
     $("#runReport").enabled = false; 
     $.ajaxSetup({"error":(function(report) { 
      return function(event, XMLHttpRequest, ajaxOptions, thrownError) { 
       report.ajaxError(event, XMLHttpRequest, ajaxOptions, thrownError); 
      }; 
     })(this)}); 

     $.getJSON("/api/leagues", {"user":user}, (function(report) { 
      return function(leagues) { 
       report.addSeriesGroup(leagues); 
      }; 
     })(this)); 
     $.getJSON("/api/tournaments", {"user":user}, (function(report) { 
      return function(tournaments) { 
       report.addSeriesGroup(tournaments); 
      }; 
     })(this)); 
     $.getJSON("/api/practices", {"user":user}, (function(report) { 
      return function(practices) { 
       report.addSerieses(practices); 
      }; 
     })(this)); 
    }; 

    // Retrieves the serieses (group of IDs) for a series group, such as a league or 
    // tournament. 
    this.addSeriesGroup = function(seriesGroups) { 
     var report = this; 
     if(seriesGroups) { 
      $.each(seriesGroups, function(index, seriesGroup) { 
       report.pendingOperations += 1; 
       $.getJSON("/api/seriesgroup", {"group":seriesGroup.key}, (function(report) { 
        return function(serieses) { 
         report.addSerieses(serieses); 
        }; 
       })(report)); 
      }); 
     } 
     this.pendingOperations -= 1; 
     this.tryFinishReport(); 
    }; 

    // Retrieves the actual serieses for a series group. Takes a set of 
    // series IDs and retrieves each series. 
    this.addSerieses = function(serieses) { 
     var report = this; 
     if(serieses) { 
      $.each(serieses, function(index, series) { 
       report.pendingOperations += 1; 
       $.getJSON("/api/series", {"series":series.key}, (function(report) { 
        return function(series) { 
         report.addSeries(series); 
        }; 
       })(report)); 
      }); 
     } 
     this.pendingOperations -= 1; 
     this.tryFinishReport(); 
    }; 

    // Adds the games for the series to the list of games 
    this.addSeries = function(series) { 
     var report = this; 
     if(series && series.games) { 
      $.each(series.games, function(index, game) { 
       report.games.push(game); 
      }); 
     } 
     this.pendingOperations -= 1; 
     this.tryFinishReport(); 
    }; 

    // Checks to see if all pending requests have completed - if so, runs the 
    // report. 
    this.tryFinishReport = function() { 
     if(this.pendingOperations > 0) { 
      return; 
     } 
     var progress = $("#reportProgress"); 
     progress.text("Performing calculations..."); 
     setTimeout((function(report) { 
      return function() { 
       report.finishReport(); 
      }; 
     })(this), 1); 
    } 

    // Performs report calculations and displays them to the user. 
    this.finishReport = function() { 
     var rC = $("#rC"); 

     //snip a page of calculations/table generation 
     rC.html(html); 

     $("#rC table").addClass("tablesorter").attr("cellspacing", "1").tablesorter({"sortList":[[3,1]]}); 
    }; 

    // Handles errors (by ignoring them) 
    this.ajaxError = function(event, XMLHttpRequest, ajaxOptions, thrownError) { 
     this.pendingOperations -= 1; 
    }; 

    return true; 
} 

// A class to track the state of the various controls. The "series set" stuff 
// is for future functionality. 
function ReportingEngine() { 
    this.seriesSet = []; 
    this.reports = {}; 
    this.getSeriesSet = function() { 
     return this.seriesSet; 
    }; 
    this.clearSeriesSet = function() { 
     this.seriesSet = []; 
    }; 
    this.addGame = function(series) { 
     this.seriesSet.push(series); 
    }; 
    this.currentUser = function() { 
     return $("#userSelect").val(); 
    }; 
    this.currentReport = function() { 
     reportName = $("#reportSelect").val(); 
     if(reportName) { 
      return this.reports[reportName]; 
     } 
     return null; 
    }; 
} 

// Sets the enablement of the run button based on the selections to the inputs 
function updateRunButton() { 
    var report = engine.currentReport(); 
    var user = engine.currentUser(); 
    setRunButtonEnablement(report != null && user != null); 
} 

function setRunButtonEnablement(enabled) { 
    if(enabled) { 
     $("#runReport").removeAttr("disabled"); 
    } else { 
     $("#runReport").attr("disabled", "disabled"); 
    } 

} 

var engine = new ReportingEngine(); 

$(document).ready(function() { 
    loadUI(); 
}); 

function runReport() { 
    var report = engine.currentReport(); 
    if(report == null) { 
     updateRunButton(); 
     return; 
    } 
    report.run(); 
} 

我要開始添加新的報告,其中一些將要操作的只是用戶的遊戲的一個子集。我將試圖使用子類(原型?),但如果我無法弄清楚如何簡化這些......我不知道如何完成這個句子。幫幫我!

回答

3
$.getJSON("/api/leagues", {"user":user}, (function(report) { 
     return function(leagues) { 
      report.addSeriesGroup(leagues); 
     }; 
    })(this)); 

可以寫成:當你是一個循環內,並且要綁定到周圍的每次循環變化的可變

var self = this; 
$.getJSON("/api/leagues", {"user":user}, (function(leagues) { 
      self.addSeriesGroup(leagues); 
     }); 

功能,返回功能是比較有用的。

+0

謝謝。我知道必須有一個更簡單的方法! – 2009-04-16 22:43:41

2

在必要時提供「一些」評論。

+0

添加了一些評論,對不起。 – 2009-04-16 22:42:26

1

我會對你說實話,說我沒有讀完整件事。不過,我認爲你應該知道JavaScript的一些東西,那就是它已經關閉了。

var x = 1; 
$.ajax({ 
    success: function() { 
    alert(x); 
    } 
}); 

不管需要多長時間爲AJAX請求的完成,將有機會獲得x並會提醒「1」,一旦成功。

+1

他實際上已經在使用閉包,只是以一種更爲複雜的方式來使用 – Greg 2009-04-16 20:54:52

1

瞭解閉包。這需要一些習慣。 (很多人會使用這種方法,而且肯定是開展事情的典型方式,所以如果你瞭解情況如何,這很好)

This is a good thread閱讀以獲取有關如何有效使用它們的簡單說明。

1

您應該使用prototypes定義方法,做繼承:

function Parent(x) { 
    this.x = x; /* Set an instance variable. Methods come later. */ 
} 

/* Make Parent inherit from Object by assigning an 
* instance of Object to Parent.prototype. This is 
* very different from how you do inheritance in 
* Java or C# ! 
*/ 
Parent.prototype = { /* Define a method in the parent class. */ 
    foo: function() { 
    return 'parent ' + this.x; /* Use an instance variable. */ 
    } 
} 

function Child(x) { 
    Parent.call(this, x) /* Call the parent implementation. */ 
} 

/* Similar to how Parent inherits from Object; you 
* assign an instance of the parent class (Parent) to 
* the prototype attribute of the child constructor 
* (Child). 
*/ 
Child.prototype = new Parent(); 

/* Specialize the parent implementation. */ 
Child.prototype.foo = function() { 
    return Parent.prototype.foo.call(this) + ' child ' + this.x; 
} 

/* Define a method in Child that does not override 
* something in Parent. 
*/ 
Child.prototype.bar = function() { 
    return 'bar'; 
} 

var p = new Parent(1); 
alert(p.foo()); 

var ch = new Child(2); 
alert(ch.foo()); 
alert(ch.bar()); 

我不熟悉的jQuery,但我知道Prototype library(最差名選擇曾經)有一定的功能,使其更易於工作與繼承。

另外,當想出這個問題的答案時,我發現了一個很好的網頁,可以在how to do OO right in JS上找到更詳細的信息,您可以查看它。

相關問題