2013-02-13 18 views
8

Tôi đã mổ xẻ đoạn mã sau đây, được sử dụng để đồng bộ nạp Segment.io phân tích wrapper kịch bản:Tại sao tập lệnh bộ nạp Segment.io đẩy tên phương thức/arg vào hàng đợi có vẻ bị ghi đè?

// Create a queue, but don't obliterate an existing one! 
var analytics = analytics || []; 

// Define a method that will asynchronously load analytics.js from our CDN. 
analytics.load = function(apiKey) { 

    // Create an async script element for analytics.js. 
    var script = document.createElement('script'); 
    script.type = 'text/javascript'; 
    script.async = true; 
    script.src = ('https:' === document.location.protocol ? 'https://' : 'http://') + 
        'd2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/' + apiKey + '/analytics.min.js'; 

    // Find the first script element on the page and insert our script next to it. 
    var firstScript = document.getElementsByTagName('script')[0]; 
    firstScript.parentNode.insertBefore(script, firstScript); 

    // Define a factory that generates wrapper methods to push arrays of 
    // arguments onto our `analytics` queue, where the first element of the arrays 
    // is always the name of the analytics.js method itself (eg. `track`). 
    var methodFactory = function (type) { 
     return function() { 
      analytics.push([type].concat(Array.prototype.slice.call(arguments, 0))); 
     }; 
    }; 

    // Loop through analytics.js' methods and generate a wrapper method for each. 
    var methods = ['identify', 'track', 'trackLink', 'trackForm', 'trackClick', 
        'trackSubmit', 'pageview', 'ab', 'alias', 'ready']; 

    for (var i = 0; i < methods.length; i++) { 
     analytics[methods[i]] = methodFactory(methods[i]); 
    } 
}; 

// Load analytics.js with your API key, which will automatically load all of the 
// analytics integrations you've turned on for your account. Boosh! 
analytics.load('MYAPIKEY'); 

Nó cũng nhận xét và tôi có thể nhìn thấy những gì nó làm, nhưng tôi bối rối khi nói với hàm methodFactory, sẽ đẩy chi tiết (tên phương thức và đối số) của bất kỳ lệnh gọi phương thức nào được thực hiện trước khi tập lệnh chính analytics.js đã được tải lên mảng toàn cầu analytics.

này là tất cả tốt và tốt, nhưng sau đó nếu/khi kịch bản chính không tải, nó dường như chỉ ghi đè analytics biến toàn cầu (xem last line here), do đó tất cả dữ liệu sẽ bị mất.

tôi thấy cách này ngăn chặn lỗi kịch bản trong một trang web bằng cách loại bỏ dần từng phương pháp mà không tồn tại, nhưng tôi không hiểu tại sao cuống không thể chỉ trả lại một chức năng rỗng:

var methods = ['identify', 'track', 'trackLink', 'trackForm', 'trackClick', 
       'trackSubmit', 'pageview', 'ab', 'alias', 'ready']; 

for (var i = 0; i < methods.length; i++) { 
    lib[methods[i]] = function() { }; 
} 

Tôi đang thiếu gì? Xin hãy giúp tôi hiểu!

Trả lời

22

Ian ở đây, đồng sáng lập tại Segment.io — Tôi không thực sự viết mã đó, Calvin đã làm, nhưng tôi có thể điền vào bạn những gì nó đang làm.

Bạn nói đúng, các methodFactory được loại bỏ dần từng phương pháp để họ có sẵn trước khi tải kịch bản, có nghĩa là mọi người có thể gọi analytics.track mà không cần gói những cuộc gọi trong một if hoặc ready() gọi.

Nhưng các phương pháp thực sự tốt hơn so với "câm" sơ khai, trong đó họ lưu phương pháp được gọi, vì vậy chúng tôi có thể phát lại các hành động sau này. Đó là một phần này:

analytics.push([type].concat(Array.prototype.slice.call(arguments, 0))); 

Để thực hiện điều đó dễ đọc hơn:

var methodFactory = function (method) { 
    return function() { 
     var args = Array.prototype.slice.call(arguments, 0); 
     var newArgs = [method].concat(args); 
     analytics.push(newArgs); 
    }; 
}; 

Nó đinh vào tên của phương pháp này được gọi là, có nghĩa là nếu tôi analytics.identify('userId'), hàng đợi của chúng tôi thực sự trở nên một mảng trông như:

['identify', 'userId'] 

Sau đó, khi tải thư viện của chúng tôi ở, nó trút tất cả các cuộc gọi xếp hàng đợi và replay chúng thành những phương pháp thực tế (mà bây giờ đã có) để tất cả các dữ liệu ghi trước khi tải vẫn được bảo quản. Đó là phần quan trọng, bởi vì chúng tôi không muốn chỉ vứt bỏ bất kỳ cuộc gọi nào xảy ra trước khi thư viện của chúng tôi có cơ hội để tải. Trông như thế này:

// Loop through the interim analytics queue and reapply the calls to their 
// proper analytics.js method. 
while (window.analytics.length > 0) { 
    var item = window.analytics.shift(); 
    var method = item.shift(); 
    if (analytics[method]) analytics[method].apply(analytics, item); 
} 

analytics là một biến địa phương tại thời điểm đó, và sau khi chúng tôi xong phát lại, chúng tôi thay thế toàn cầu với các địa phương analytics (mà là ảnh thật).

Hy vọng điều đó có ý nghĩa. Chúng tôi thực sự sẽ có một chuỗi trên blog của chúng tôi về tất cả các thủ thuật nhỏ dành cho Javascript của bên thứ ba, vì vậy bạn có thể sớm khai thác!

+0

Tuyệt vời! Cảm ơn bạn đã giải thích, Ian, tôi mong chờ các bài đăng trên blog. Tôi nghĩ rằng nó sẽ là một cái gì đó dọc theo những dòng, nhưng bit địa phương-to-toàn cầu đã ném tôi, cộng với tôi không thể (và vẫn không thể) thấy một đoạn mã mà thực sự áp dụng các cuộc gọi bất cứ nơi nào. Đây có phải là nội dung cụ thể cho Segment.io chứ không phải trong mã thư viện analytics.js chuẩn hay tôi chỉ thiếu nó? –

+1

Ah, yup nó cụ thể cho đoạn trích của chúng tôi trên Segment.io. Nếu bạn đang sử dụng độc lập, thư viện không được tải không đồng bộ, do đó bạn không cần phát lại hàng đợi. –

+0

Đúng, có ý nghĩa ngay bây giờ! –

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