2016-01-04 16 views
7

chúng tôi đang sử dụng require.js trong dự án của chúng tôi và chúng tôi cần phải ghi đè lên setTimeout trong dòng 705, đây là đoạn code mà chúng ta cần phải phớt lờ/bỏ qua bằng cách nào đó setTimeout này ở tất cả (Tôi có nghĩa là chạy qua nó), vấn đề là nếu tôi thay đổi nó trong mã nguồn mở rõ ràng khi tôi thay đổi phiên bản mã sẽ bị mất, Làm thế nào tôi nên ghi đè setTimout này từ bên ngoài chỉ cho tập tin require.js và giữ nó lâu khi tôi sử dụng lib này, có thể thực hiện điều đó trong cách thanh lịch trong JS trên toàn cầu không?override setTimeout trong require.js

https://github.com/jrburke/requirejs/blob/master/require.js

Đây là dòng 705

 //If still waiting on loads, and the waiting load is something 
     //other than a plugin resource, or there are still outstanding 
     //scripts, then just try back later. 
     if ((!expired || usingPathFallback) && stillLoading) { 
      //Something is still waiting to load. Wait for it, but only 
      //if a timeout is not already in effect. 
      if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { 
       checkLoadedTimeoutId = setTimeout(function() { 
        checkLoadedTimeoutId = 0; 
        checkLoaded(); 
       }, 50); 
      } 
     } 

FYI, Lý do mà chúng tôi làm điều đó là Chrome: timeouts/interval suspended in background tabs?

+0

Đó gọi cho tất cả các chuông báo động của tôi, tại sao bạn cần phải làm điều đó? Thay đổi các chức năng và đối tượng toàn cục là * gần như không bao giờ * là một ý tưởng hay. –

+0

@MadaraUchiha - xem các liên kết mà tôi đã cung cấp với setTimout, khi chúng tôi sử dụng require.js trên tab không hoạt động (ý tôi là sau khi mở cửa sổ mới), mọi tải dịch vụ đều mất một giây! –

+0

Nhưng, trong tab không hoạt động, người dùng không xem, tại sao bạn quan tâm phải mất bao lâu? –

Trả lời

5

Bạn đã nói mục tiêu của bạn là làm việc xung quanh việc điều chỉnh mà Chrome thực hiện trên setTimeout cho các tab đang ở chế độ nền. Tôi không nghĩ rằng nó là một ý tưởng tốt để làm như vậy, nhưng nếu bạn phải, sau đó bạn chắc chắn nên vá RequireJS thay vì rối tung với setTimeout trên toàn cầu.Bạn nói:

nếu tôi thay đổi nó trong mã nguồn mở rõ ràng khi tôi thay đổi phiên bản mã sẽ bị mất

Điều này đúng chỉ khi bạn không sử dụng một phương pháp hợp lý để thực hiện các thay đổi . Có thể làm điều đó một cách hợp lý. Ví dụ, bạn có thể sử dụng Gulp để lấy tệp require.js được cài đặt trong node_modules (sau khi bạn cài đặt RequireJS với npm) và tạo một tệp được vá trong build. Sau đó, bạn sử dụng tệp được vá này trong ứng dụng của mình. Đây là số gulpfile.js:

var gulp = require("gulp"); 

// Bluebird is a good implementation of promises. 
var Promise = require("bluebird"); 

// fs-extra produces a `fs` module with additional functions like 
// `ensureDirAsync` which is used below. 
var fs = require("fs-extra"); 

// Make it so that for each the function in fs that is asynchronous 
// and takes a callback (e.g. `fs.readFile`), a new function that 
// returns promise is created (e.g. `fs.readFileAsync`). 
Promise.promisifyAll(fs); 

var to_replace = 
"if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {\n\ 
        checkLoadedTimeoutId = setTimeout(function() {\n\ 
         checkLoadedTimeoutId = 0;\n\ 
         checkLoaded();\n\ 
        }, 50);"; 

var replace_with = 
"if (isBrowser || isWebWorker) {\n\ 
        checkLoaded();"; 


gulp.task("default", function() { 
    // Use `fs.ensureDirAsync` to make sure the build directory 
    // exists. 
    return fs.ensureDirAsync("build").then(function() { 
     return fs.readFileAsync("node_modules/requirejs/require.js") 
      .then(function (data) { 
       data = data.toString(); 

       // We use the split/join idiom to a) check that we get 
       // the string to be replaced exactly once and b) 
       // replace it. First split... 
       var chunks = data.split(to_replace); 

       // Here we check that the results of splitting the 
       // chunk is what we expect. 
       if (chunks.length < 2) { 
        throw new Error("did not find the pattern"); 
       } 
       else if (chunks.length > 2) { 
        throw new Error("found the pattern more than once"); 
       } 

       // We found exactly one instance of the text to 
       // replace, go ahead. So join... 
       return fs.writeFileAsync("build/require.js", 
             chunks.join(replace_with)); 
      }); 
    }); 
}); 

Bạn cần phải chạy npm install gulp fs-extra bluebird requirejs trước khi chạy. Ở mức nào, bạn có thể sử dụng Gulp, bạn có thể sử dụng Grunt hoặc bạn có thể sử dụng bất kỳ hệ thống nào khác mà bạn muốn thực hiện một bản dựng. Những điểm là:

  1. Bạn có một phương pháp tái sản xuất và tự động để vá RequireJS. Nếu bạn cài đặt phiên bản mới của RequireJS với npm, khi bạn xây dựng lại phần mềm, bản vá sẽ được áp dụng tự động, miễn là mã RequireJS không thay đổi theo cách ngăn cản áp dụng bản vá. Xem điểm tiếp theo cho những gì sẽ xảy ra nếu một thay đổi ngăn cản việc áp dụng các miếng vá.

  2. Phương pháp này mạnh mẽ hơn ghi đè setTimeout khi chạy. Giả sử James Burke quyết định trong phiên bản mới hơn của RequireJS để đổi tên checkLoaded thành checkDone và đổi tên các biến được liên kết (để checkLoadedTimeoutId trở thành checkDoneTimeoutId). Các gulpfile ở trên sẽ tăng một ngoại lệ khi bạn chạy nó một lần nữa bởi vì nó sẽ không tìm thấy văn bản được thay thế. Bạn sẽ phải cập nhật văn bản để thay thế và thay thế để bản vá hoạt động với phiên bản mới của RequireJS. Lợi ích ở đây là bạn nhận được cảnh báo sớm rằng mọi thứ đã thay đổi và bạn cần xem lại bản vá. Bạn sẽ không có bất ngờ vào cuối trò chơi, có lẽ sau khi bạn đã gửi phiên bản phần mềm mới cho khách hàng.

    Các phương pháp ghi đè setTimeout vào thời gian chạy sẽ âm thầm không thực hiện được công việc của mình. Họ sẽ tìm kiếm một hàm có chứa checkLoadedTimeoutId, chức năng này sẽ không còn tồn tại trong phiên bản mới. Vì vậy, họ sẽ chỉ cho phép RequireJS hoạt động theo cách mặc định. Sự thất bại sẽ là một sự tinh tế. (Tôi đã chạy RequireJS với các phiên bản tùy chỉnh đề xuất của setTimeout với một dự án mà tải lên tới 50 module khi không được tối ưu hóa. Tôi thấy không có sự khác biệt rõ rệt giữa RequireJS sử dụng chứng khoán setTimeout và RequireJS sử dụng một tùy chỉnh setTimeout.)

  3. Phương pháp này không làm chậm mọi lần sử dụng setTimeout.setTimeout được sử dụng bởi mã khác so với RequireJS. Không có vấn đề làm thế nào bạn cắt nó, thêm mã trong một thay thế tùy chỉnh để setTimeout mà bắt đầu tìm kiếm các chuỗi trong mỗi chức năng được truyền cho nó sẽ làm cho tất cả sử dụng setTimeout chậm hơn.

+0

Phương thức thanh lịch! Nó không cần phải chỉnh sửa các tập tin và thay đổi setTimeout chính nó ... Chỉ có một thời điểm mà bạn cần gulp/grunt/nhiệm vụ khác quản lý trong dự án. –

1

Nếu bạn thực sự cần điều này ... Hãy thử thêm trước khi bốc requirejs:

function isTimeoutIgnoredFunction(fn, time) { 
    // you should configure this condition for safety, to exclude ignoring different timeOut calls! 
    return time == 50 && fn.toString().indexOf('checkLoadedTimeoutId') > -1; 
} 

window.setTimeoutOriginal = window.setTimeout; 

window.setTimeout = function(fn, time) { 
    if (isTimeoutIgnoredFunction(fn, time)) { 
     return fn(); // or return true if you don't need to call this 
    } else { 
     return window.setTimeoutOriginal.apply(this, arguments); 
    } 
}; 

Sho uld làm việc trong Chrome cuối cùng, Firefox, IE nếu không có requirejs minify cung cấp ... Bạn cần phải viết lại chức năng "isTimeoutIgnoredFunction" cho các trình duyệt bạn hỗ trợ và cho tập tin require.js được rút gọn.

Để xem những gì chuỗi bạn có thể sử dụng:

console.log((function() { 
        checkLoadedTimeoutId = 0; 
        checkLoaded(); 
       }).toString()); 

Nhưng trong một số trình duyệt nó có thể chỉ là một cái gì đó như "Chức năng".

Nếu bạn chưa có nhiều setTimeout của nó có thể là giải pháp phù hợp ...

2

Bạn có thể ghi đè lên setTimeout và kiểm tra xem các chức năng thông qua như là gọi lại chứa một biến được sử dụng trong chức năng đó từ require.js (checkLoadedTimeoutId). Nếu có, hãy gọi hàm ngay lập tức, nếu không, hãy gọi hàm setTimeout gốc.

(function(setTimeoutCopy) { 
    setTimeout = function(fn, timeout) { 
    if (fn.toString().indexOf("checkLoadedTimeoutId") >= 0) { 
     return fn(); 
    } else { 
     return setTimeoutCopy.apply(null, arguments); 
    } 
    }; 
}(setTimeout)); 

Lưu ý rằng có nhiều vấn đề với mã này. Nếu bạn chuyển một hàm đến setTimeout có chứa checkLoadedTimeoutId, nó cũng sẽ được thực thi ngay lập tức. Ngoài ra, nếu mã require.js được rút gọn và các biến được đổi tên, nó sẽ không hoạt động.

Tóm lại, không có cách nào tốt để thực hiện việc này. Có thể cố gắng tìm một cách khác để đạt được những gì bạn muốn. Cũng lưu ý rằng, như Madara Uchiha đã nói:

Thay đổi chức năng và đối tượng toàn cầu là hầu như không bao giờ một ý tưởng hay.

1

cách khác để đạt được nó được thực hiện một yêu cầu ajax của thư viện và vá nó trước khi tải thư viện, nhưng bạn sẽ cần phải có được nạp một cách để thực hiện yêu cầu (js vani hoặc jquery ...)

Mã tiếp theo là ví dụ về tải requirejs và vá nó bằng regexp trước khi tải nó trong DOM.

$(function(){ 
 
    // here you can put the url of your own hosted requirejs or a url from a CDN 
 
    var requirejsUrl = 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.22/require.js'; 
 
    
 
    function patch(lib){ 
 
    var toReplace = /if\s*\(\(isBrowser\s*\|\|\s*isWebWorker\)\s*\&\&\s*!checkLoadedTimeoutId\)\s*\{([^{}]|\{[^{}]*\})*\}/; 
 
    var by = 'if (isBrowser || isWebWorker) { checkLoaded();}'; 
 
    return lib.replace(toReplace, by); 
 
    } 
 
    
 
    $.get(requirejsUrl, function(lib){ 
 
    var libpatched = patch(lib); 
 
    
 
    var script=document.createElement('script'); 
 
    script.innerText=libpatched; 
 
    $('body').append(script); 
 
    
 
    console.log(window.require); // requirejs patched is loaded 
 
    }); 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

+0

Mã trong câu trả lời này tải RequireJS không đồng bộ, có nghĩa là bất kỳ mã nào phụ thuộc vào RequireJS sẽ phải đợi RequireJS có mặt trước khi chạy. Nói lời tạm biệt với sự đơn giản của '' (một mẫu khá phổ biến, mà tôi tình cờ sử dụng). – Louis