2010-07-08 30 views
26

Tôi hiện đang duy trì một số lượng lớn các tệp JS và sự cố phụ thuộc đang tăng lên trên đầu của tôi. Ngay bây giờ tôi có từng chức năng trong một tệp riêng biệt và tôi duy trì cơ sở dữ liệu theo cách thủ công để tìm ra các phụ thuộc giữa các hàm.Quản lý phụ thuộc JavaScript

Điều này tôi muốn tự động hóa. Ví dụ nếu tôi có hàm f

Array.prototype.f = function() {}; 

được tham chiếu trong một hàm g

MyObject.g = function() { 
    var a = new Array(); 
    a.f(); 
}; 

Tôi muốn để có thể phát hiện rằng g là tham khảo f.

Tôi làm cách nào để thực hiện việc này? Tôi bắt đầu từ đâu? Tôi có cần phải viết một trình biên dịch hay tôi có thể tinh chỉnh Spidermonkey không? Có ai khác đã làm điều này không?

Bất kỳ con trỏ để tôi bắt đầu được rất nhiều đánh giá cao

Cảm ơn Dok

+0

Bạn có muốn tạo biểu đồ thể hiện chức năng nào được gọi bằng các chức năng khác không? Đó là những gì tôi hiện đang cố gắng làm, và tôi tự hỏi nếu bạn đang cố gắng để giải quyết cùng một vấn đề mà tôi. :) –

+1

@AndersonGreen Bạn đang tìm kiếm một cái gì đó như [Code2Flow] (https://github.com/scottrogowski/code2flow)? –

Trả lời

18

Trong khi bạn về mặt lý thuyết có thể viết một công cụ phân tích tĩnh mà phát hiện sử dụng như là toàn thể được định nghĩa trong các tập tin khác, chẳng hạn như sử dụng MyObject, bạn thực tế không thể theo dõi việc sử dụng phương thức mở rộng prototype.

JavaScript là một ngôn ngữ động, đánh máy nên không có cách nào thiết thực cho bất kỳ công cụ để biết rằng a, nếu ngất xỉu của g chức năng, là một Array, và vì vậy nếu f() được gọi vào nó có một sự phụ thuộc. Nó chỉ được xác định những gì biến giữ những loại tại thời gian chạy, do đó, để tìm ra bạn cần một thông dịch viên và bạn đã làm cho mình một vấn đề Turing-hoàn thành.

Chưa kể các khía cạnh động khác của JavaScript hoàn toàn phân tích tĩnh phân tích, chẳng hạn như tìm nạp thuộc tính theo ký hiệu ngoặc vuông, số eval hoặc chuỗi trong thời gian chờ hoặc thuộc tính xử lý sự kiện.

Tôi nghĩ rằng đó là một chút không khởi động thực sự. Bạn có thể tốt hơn việc theo dõi các phụ thuộc theo cách thủ công, nhưng đơn giản hóa nó bằng cách nhóm các hàm liên quan thành các mô-đun sẽ là đơn vị theo dõi phụ thuộc cơ bản của bạn. OK, bạn sẽ kéo thêm một vài chức năng mà bạn cần kỹ thuật, nhưng hy vọng không quá nhiều. Nó cũng là một ý tưởng tốt để không gian tên mỗi mô-đun, do đó, nó rất rõ ràng nơi mà mỗi cuộc gọi đang đi, làm cho nó dễ dàng để giữ cho các phụ thuộc trong kiểm soát bằng tay (ví dụ: một bình luận // uses: ThisModule, ThatModule ở đầu trang).

Vì các phần mở rộng của các mẫu thử được tích hợp sẵn hơn để theo dõi, hãy giữ chúng ở mức tối thiểu. Mở rộng ví dụ. Array để bao gồm các phương thức ECMAScript Fifth Edition (như indexOf) trên các trình duyệt chưa có chúng là một việc tốt để làm bản sửa lỗi cơ bản mà tất cả các tập lệnh sẽ sử dụng. Thêm chức năng tùy ý hoàn toàn mới vào các nguyên mẫu hiện có là vấn đề.

+0

Cảm ơn câu trả lời của bạn ... Tôi sẽ đi một con đường khác. – user386508

8

Như @bobince đã đề xuất, thực hiện phân tích tĩnh trên một chương trình JavaScript là một vấn đề gần như không thể crack. Google Closure compiler ở mức độ nào đó nhưng sau đó nó cũng dựa trên trợ giúp từ bên ngoài từ JSDoc nhận xét.

Tôi đã có một similar problem để tìm thứ tự các tệp JS được ghép nối trong một dự án trước đó và vì có rất nhiều tệp JS, việc cập nhật thủ công thứ tự bao gồm dường như quá tẻ nhạt. Thay vào đó, tôi bị mắc kẹt với một số quy ước về những gì cấu thành một sự phụ thuộc cho các mục đích của tôi, và dựa trên đó và sử dụng đơn giản regexp :) Tôi đã có thể tạo ra thứ tự bao gồm chính xác.

Giải pháp đã sử dụng thuật toán topological sort để tạo một dependency graph, sau đó liệt kê các tệp theo thứ tự mà chúng cần được bao gồm để đáp ứng tất cả các phụ thuộc. Vì mỗi tệp cơ bản là một lớp giả sử dụng cú pháp MooTools, chỉ có 3 cách phụ thuộc có thể được tạo cho tình huống của tôi.

  1. Khi một lớp học Mở rộng một số lớp khác.
  2. Khi một lớp Thực hiện một số lớp khác.
  3. Khi lớp học khởi tạo đối tượng của một số lớp khác bằng cách sử dụng từ khóa new.

Đó là giải pháp đơn giản và chắc chắn bị hỏng vì mục đích sử dụng chung nhưng nó đã phục vụ tốt cho tôi. Nếu bạn quan tâm đến giải pháp, bạn có thể xem số code here - đó là trong Ruby.

Nếu phụ thuộc của bạn là phức tạp hơn, thì có lẽ bạn có thể tự liệt kê các phụ thuộc trong mỗi JS tự nộp bằng các comment và một số cú pháp cây nhà lá vườn như:

// requires: Array 
// requires: view/TabPanel 
// requires: view/TabBar 

Sau đó đọc mỗi file JS, phân tích ra các đòi hỏi nhận xét và xây dựng biểu đồ phụ thuộc sẽ cung cấp cho bạn thứ tự bao gồm bạn cần.

5

Thật tuyệt khi có một công cụ có thể tự động phát hiện các phụ thuộc đó cho bạn và chọn cách chúng được tải. Các giải pháp tốt nhất hiện nay là một chút cruder mặc dù. Tôi đã tạo một người quản lý phụ thuộc cho các nhu cầu cụ thể của tôi mà tôi muốn thêm vào danh sách (Pyramid Dependency Manager). Nó có một số tính năng chính để giải quyết một số trường hợp sử dụng duy nhất.

  1. Xử lý các file khác (bao gồm chèn html cho quan điểm ... vâng, bạn có thể tách quan điểm của bạn trong phát triển)
  2. Kết hợp các tập tin cho bạn trong javascript khi bạn đã sẵn sàng cho phát hành (không cần cài đặt bên ngoài công cụ)
  3. Có bao gồm chung cho tất cả các trang html. Bạn chỉ phải cập nhật một tệp khi phụ thuộc được thêm, xóa, đổi tên, v.v.

Một số mã mẫu để cho biết cách hoạt động của nó trong quá trình phát triển.

File: dependencyLoader.js

//Set up file dependencies 
Pyramid.newDependency({ 
    name: 'standard', 
    files: [ 
    'standardResources/jquery.1.6.1.min.js' 
    ] 
}); 

Pyramid.newDependency({ 
name:'lookAndFeel', 
files: [ 
    'styles.css', 
    'customStyles.css', 
    'applyStyles.js' 
    ] 
}); 

Pyramid.newDependency({ 
name:'main', 
files: [ 
    'createNamespace.js', 
    'views/buttonView.view', //contains just html code for a jquery.tmpl template 
    'models/person.js', 
    'init.js' 
    ], 
    dependencies: ['standard','lookAndFeel'] 
}); 

tập tin Html

<head> 
    <script src="standardResources/pyramid-1.0.1.js"></script> 
    <script src="dependencyLoader.js"></script> 
    <script type="text/javascript"> 
     Pyramid.load('main'); 
    </script> 
</head> 

Nó yêu cầu bạn phải duy trì một tập tin duy nhất để quản lý phụ thuộc.Tôi đang nghĩ về việc tạo một chương trình có thể tự động tạo tệp trình tải cho bạn dựa trên các phần tử bao gồm trong tiêu đề nhưng vì nó xử lý nhiều loại phụ thuộc khác nhau, việc duy trì chúng trong một tệp có thể thực sự tốt hơn.

1

JSAnalyse sử dụng phân tích mã tĩnh để phát hiện phụ thuộc giữa các tập tin javascript: http://jsanalyse.codeplex.com/

Nó cũng cho phép bạn xác định các phụ thuộc cho phép và để đảm bảo nó trong xây dựng, ví dụ. Tất nhiên, nó không thể phát hiện tất cả các phụ thuộc vì javascript là ngôn ngữ diễn giải động mà không phải là loại an toàn, như đã đề cập. Nhưng nó ít nhất làm cho bạn nhận thức được đồ thị phụ thuộc javascript của bạn và giúp bạn giữ nó dưới sự kiểm soát.

10

Bạn đã thử sử dụng trình quản lý phụ thuộc như RequireJS hoặc LabJS? Tôi nhận thấy không ai đề cập đến họ trong chủ đề này.

Từ http://requirejs.org/docs/start.html:

Bên trong main.js, bạn có thể sử dụng yêu cầu() để tải bất kỳ kịch bản khác mà bạn cần phải chạy:

require(["helper/util"], function(util) { 
    //This function is called when scripts/helper/util.js is loaded. 
    //If util.js calls define(), then this function is not fired until 
    //util's dependencies have loaded, and the util argument will hold 
    //the module value for "helper/util". 
}); 

Bạn có thể làm tổ những người phụ thuộc là tốt, vì vậy helper/util có thể yêu cầu một số tập tin khác trong chính nó.

0

Tôi đã viết một công cụ để làm điều gì đó như thế này: http://github.com/damonsmith/js-class-loader

Đó là hữu ích nhất nếu bạn có một webapp java và bạn cấu trúc mã JS của bạn theo phong cách java. Nếu bạn làm điều đó, nó có thể phát hiện tất cả các phụ thuộc mã của bạn và gói chúng lại, với sự hỗ trợ cho cả phụ thuộc thời gian chạy và phân tích thời gian.

Các vấn đề liên quan