2013-03-22 33 views
13

Rủi ro khi đặt câu hỏi ngu ngốc tôi sẽ thử.requirejs tải tiến trình tập lệnh

Có thể hiển thị chỉ báo tiến trình trong khi RequireJs đang tải phụ thuộc không?

Ví dụ:

require(['jquery'], function($) { 

    // Well, jQuery loaded in quite some time due to a low-speed connection 
    // 
    // Or maybe I wanted to show an overlay to prevent user of clicking on UI widgets until the load is complete 
}); 

Tôi không muốn bắt đầu sửa đổi nguồn RequireJS nếu có một số plugin ra khỏi đó mà không hiển thị trong tìm kiếm Google của tôi.

Cảm ơn sự giúp đỡ của bạn.

Trả lời

8

Không, điều này là không thể. RequrieJs tải mô-đun bằng cách tạo thẻ tập lệnh mới trong DOM và lắng nghe sự kiện tải. Không có sự kiện cập nhật nào giữa tải bắt đầu và kết thúc. Vì vậy, nó không phải là một hạn chế của requireJs nhưng DOM.

+0

@explunit: Nếu bạn có một cái gì đó để thêm, nhận xét về câu trả lời này. Không chỉnh sửa câu trả lời. –

+0

Nếu bạn kiểm tra vùng đầu html trong công cụ Firebug hoặc Chrome dev, bạn có thể xem những gì RequireJs thực hiện với thẻ script và hiểu tại sao nó không thể có chỉ báo tiến trình. – explunit

+0

Cảm ơn sự giúp đỡ của bạn. Nó làm cho suy nghĩ của một cách tiếp cận tốt hơn - thay vì dựa vào sự kiện 'kịch bản nạp' tôi sẽ thực hiện điều này trong logic ứng dụng. – crissdev

12

Có thể hiển thị chỉ báo xoay hoặc chỉ báo tiến trình, nhưng không thể hiển thị chính thanh đó. Tôi có thể nhận được trạng thái của requirejs (hiện đang tải hoặc nhàn rỗi), nhưng không phải là% của nạp/cần thiết để được nạp mô-đun, bởi vì phụ thuộc của họ được phân tích cú pháp khi tải từng mô-đun, nhưng không phải lúc đầu.

Tuy nhiên, dù sao, trang có, ít nhất, một trình quay tròn đơn giản, tốt hơn nhiều so với trang trống, trong khi người dùng đợi.

Không có thay đổi đối với requirej cần thiết! Vì vậy ..

Giả sử chúng ta có require.conf.js tập tin với

require.config({...}) 
require(["app"], function() { 

// main entry point to your hugde app's code 
}); 

và nó được nạp bởi html sử dụng

<script data-main="require.conf" type="text/javascript" src="bower_components/requirejs/require.js"></script> 

Đây là kịch bản requirejs chuẩn. Hãy thêm chỉ báo vào số

<div id="requirejs-loading-panel"> 
    <div id="requirejs-loading-status"></div> 
    <div id="requirejs-loading-module-name"></div> 
</div> 

Ok, hãy bắt kịp chức năng của requirejs được gọi là require.onResourceLoad và thực hiện tất cả các điều cần thiết. Nó sẽ được gọi bởi requirejs khi tải từng mô-đun, chuyển ngữ cảnh của requirejs với cây dep và tất cả các nhân viên khác. Chúng tôi sẽ sử dụng ngữ cảnh để tìm hiểu, cho dù requirejs đang tải một cái gì đó hay không. Tôi đã làm nó trong cuộc gọi hẹn giờ theo lịch trình, bởi vì onResourceLoad() được gọi chỉ trong khi tải, không phải khi nó được thực hiện tải. Mã này cần phải được thêm vào require.js.conf:

require.onResourceLoad = function (context, map, depMaps) { 


    var loadingStatusEl = document.getElementById('requirejs-loading-status'), 
     loadingModuleNameEl = document.getElementById('requirejs-loading-module-name'); 
    var panel = document.getElementById('requirejs-loading-panel'); 

    if (loadingStatusEl && loadingModuleNameEl) { 


     if (!context) { // we well call onResourceLoad(false) by ourselves when requirejs is not loading anything => hide the indicator and exit 

      panel.style.display = "none"; 
      return; 
     } 

     panel.style.display = ""; // show indicator when any module is loaded and shedule requirejs status (loading/idle) check 
     clearTimeout(panel.ttimer); 
     panel.ttimer = setTimeout(function() { 


      var context = require.s.contexts._; 
      var inited = true; 
      for (name in context.registry) { 
       var m = context.registry[name]; 

       if (m.inited !== true) { 
        inited = false; 
        break; 
       } 

      } // here the "inited" variable will be true, if requirejs is "idle", false if "loading" 

      if (inited) { 
       require.onResourceLoad(false); // will fire if module loads in 400ms. TODO: reset this timer for slow module loading 
      } 

     }, 400) 
     if (map && map.name) { // we will add one dot ('.') and a currently loaded module name to the indicator 

      loadingStatusEl.innerHTML = loadingStatusEl.innerHTML += '.'; //add one more dot character 
      loadingModuleNameEl.innerHTML = map.name + (map.url ? ' at ' + map.url : ''); 
     } 
    } else { 


    } 


}; 

Một vấn đề là: chúng tôi không thể tìm ra số lượng mô-đun cần tải, vì vậy chúng tôi không thể tính% tiến trình tải thực tế. Nhưng, ít nhất, chúng ta có thể tìm hiểu, cho dù chúng ta đang tải thứ gì đó hay không (và sự kiện hiện đang tải tên mô-đun) và hiển thị nó cho người dùng hồi hộp

+0

Cảm ơn. Tôi đã sử dụng điều này một thời gian trước đây và có lẽ tôi sẽ sử dụng nó để phát triển trong tương lai. – crissdev

+0

Có một sai lầm ở đây tôi nghĩ rằng: nếu (inited! == true) nên được m.inited! == true. Tại sao bạn thậm chí cần m khác? – Pietrko

+0

Một điều nữa là: hãy xem xét trường hợp khi tải mô-đun cuối cùng và bộ hẹn giờ cuối cùng được đặt. Điều gì sẽ xảy ra nếu module vẫn tải sau 400ms? Sau đó, chúng tôi không bao giờ nhận được require.onResourceLoad (false) bị sa thải. – Pietrko

10

Vì câu 2.1.19 RequireJS có thuộc tính cấu hình onNodeCreated. Nếu bạn gán một hàm cho nó, hàm đó sẽ được gọi mỗi khi một phần tử <script> được nối thêm vào một tài liệu để nạp một mô-đun.

Chức năng sẽ được cung cấp với các đối số node, config, moduleNameurl. Bằng cách gắn trình nghe sự kiện vào node, bạn có thể phát hiện thời điểm tập lệnh đã được tải hoặc không tải được.

Bây giờ bạn có thể phát hiện khi quá trình tải bắt đầu và dừng lại và có thể sử dụng thông tin đó để thông báo cho người sử dụng:

require.config({ 
    /* ... paths, shims, etc. */ 
    onNodeCreated: function(node, config, moduleName, url) { 
    console.log('module ' + moduleName + ' is about to be loaded'); 

    node.addEventListener('load', function() { 
     console.log('module ' + moduleName + ' has been loaded'); 
    }); 

    node.addEventListener('error', function() { 
     console.log('module ' + moduleName + ' could not be loaded'); 
    }); 
    }, 
}); 

Đối với IE < 9 bạn cần mã bổ sung để đính kèm nghe sự kiện.

Lưu ý: tính năng này chỉ hoạt động đối với các mô-đun được Yêu cầu trực tiếp. Plugins (requirejs/text và như vậy) đều sử dụng cơ chế tải riêng của chúng và không kích hoạt onNodeCreated. Một số kích hoạt onXhronXhrComplete mặc dù, vì vậy bạn có thể xử lý chúng quá:

require.config({ 
    /* ... paths, shims, etc. */ 
    config: { 
    text: { 
     onXhr: function(xhr, url) { 
     console.log('file ' + url + ' is about to be loaded'); 
     }, 
     onXhrComplete: function(xhr, url) { 
     console.log('file ' + url + ' has been loaded'); 
     } 
    } 
    } 
}); 
+0

Cảm ơn @keleran. Có vẻ như chức năng này đã được thêm vào để hỗ trợ [Subresource Integrity] (https://w3c.github.io/webappsec-subresource-integrity/) (theo https://github.com/jrburke/requirejs/issues/1361) – crissdev

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