Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimise a function in Javascript

I'm quite new to javascript, but have managed to write a working xml function :)

I was hoping someone could please give me a rundown of how to optimise the function. At present there's a different function for each state's weather, but I was hoping I could simplify this somehow.

Code is pasted here: http://pastie.org/private/ffuvwgbeenhyo07vqkkcsw

Any help is greatly appreciated. Thank you!

EDIT: ADDING CODE EXAMPLES OF BOTH XML FEEDS:

Function 1 (UV): http://pastie.org/private/jc9oxkexypn0cw5yaskiq

Function 2 (weather): http://pastie.org/private/pnckz4k4yabgvtdbsjvvrq

like image 369
Nelga Avatar asked Nov 05 '10 01:11

Nelga


People also ask

What is optimization in JavaScript?

Optimization is a special type of JavaScript minification. These kind of minimizers not only delete unuseful white spaces, commas, comments etc. but also help to avoid “dead code”: Google Closure Compiler.

Which optimizer is used in JavaScript?

It is important to use an application performance management tool when it comes to optimizing JavaScript performance. Application Performance Management tools like Retrace come with Real User Monitoring (RUM).

How do you optimize a script?

Arranging the styles and scripts in a particular order is one way to improve the page loading speed. It is recommended to keep the style sheets at the top and scripts after them. This is because when the browser renders your webpage it first gets the HTML and then comes the CSS, JS, images, etc.


4 Answers

$(d).find('location#sydney')

Is questionable. #sydney means an element with an attribute valued sydney that has the schema type ID. In HTML, the id="..." attribute has schema type ID thanks to the DOCTYPE. But this XML file has no DOCTYPE and hence its id="..." attributes don't have schema type ID. Consequently getElementById('sydney') won't work, and #sydney as a selector shouldn't work.

It works in practice because when you use find() jQuery falls back to its own ‘Sizzle’ JavaScript selector matcher, which simply looks for id="..." attributes as if it were HTML. But Sizzle is slow and you shouldn't rely on this implementation detail. Using the explicit attribute selector location[id=sydney] is better for an XML document.

var sydneyuv = sydneyuv += '<span>' + uvindex + '</span>' ;

You've got a superfluous assignment here. You use the augmented assignment += to add something to sydneyuv, and then you assign the result to sydneyuv again.

Also, it's generally best not to stitch together strings of HTML from input values. What if uvindex had HTML-special characters in? (It probably won't, but there's nothing stopping the site you're scraping from including them.) Without HTML-escaping you'd have HTML-injection and potentially XSS security holes. Always use DOM-style methods, like text() and attr() in jQuery, or the creation shortcut: var $sydneyuv= $('<span/>', {text: uvindex});, in preference to string-slinging.

I was hoping I could simplify this somehow.

Sure. Make it data-driven:

var towns= ['sydney', 'melbourne', 'brisbane', 'perth', 'adelaide', 'darwin'];
var uvlevels= [
    {uvlevel: 2,    risk: 'Low',         curcon: 'You can safely stay outdoors and use an SPF 15 moisturiser.'},
    {uvlevel: 5,    risk: 'Moderate',    curcon: 'Wear protective clothing outdoors and use an SPF 15 or SPF 30 moisturiser.'},
    {uvlevel: 7,    risk: 'High',        curcon: 'Wear protective clothing, limit your time outdoors and use an SPF 30 moisturiser.'},
    {uvlevel: 10,   risk: 'Very high',   curcon: 'Use caution, limit exposure to the sun and use an SPF 30 moisturiser.'},
    {uvlevel: 20,   risk: 'Extreme',     curcon: 'Use extreme caution, avoid exposure to the sun and use an SPF 30 moisturiser.'},
    {uvlevel: null, risk: 'Unavailable', curcon: 'Information is currently unavailable.'}
];

Now you can replace all those separate statements with one loop:

$.each(towns, function() {
    var $location= $(d).find('location[id='+this+']');
    var uv= $location.find('index').text();
    var shorttown= this.slice(0, 3);
    $('#uv-'+shortttown).empty().append($('<span/>', {text: uv}));
    $.each(uvlevels, function() {
        if (this.uvlevel===null || uv<=this.uvlevel) {
            $('#risk-'+shorttown).text(this.risk);
            $('#curcon-'+shorttown).text(this.curcon);
            return false;
        }
    });
});

and presumably similar for whatever the weather one's doing.

(I'd use the full town ID in the HTML document IDs, so you don't need the shorttown hack.)

like image 102
bobince Avatar answered Sep 19 '22 06:09

bobince


A simplified version would look something like this:

var cities = ['sydney', 'melbourne', 'brisbane', 'perth', 'adelaide', 'darwin'], 
    risks = {
        2: {
            risk: 'Low', 
            curcon: 'You can safely stay outdoors and use an SPF 15 moisturiser.'
        }
        5: {
            risk: 'Moderate', 
            curcon: 'Wear protective clothing outdoors and use an SPF 15 or SPF 30 moisturiser.'
        }
        7: {
            risk: 'High', 
            curcon: 'Use caution, limit exposure to the sun and use an SPF 30 moisturiser.'
        }
        10: {
            risk: 'Very High', 
            curcon: 'Use caution, limit exposure to the sun and use an SPF 30 moisturiser.'
        }
        20: {
            risk: 'Extreme', 
            curcon: 'Use extreme caution, avoid exposure to the sun and use an SPF 30 moisturiser.'
        }
    };

for(var i = 0; i < cities.length; i++){
    var shortCityName = cities[i].substring(0, 3);

    $(d).find('location#sydney').each(function(){
        var $location = $(this); 
        var uvindex = parseInt($location.find('index').text(), 10);

        $('#uv-' + shortCityName).html('<span>' + uvindex + '</span>');

        for(var i in risks){
            if(uvindex < risks[i]){
                $('#risk-' + shortCityName).html(risks[i].risk);
                $('#curcon-' + shortCityName).html(risks[i].curcon);
            }
        }
    });
}

Using an object to store the messages, then an array to store the names of the cities. Also, instead of using this:

var wicon = wicon += '<img src="' + icon + '" alt="Weather Unavailable" />' ;

You can use this instead:

var wicon = $('<img /').attr({
    src: icon, 
    alt: 'Weather Unavailable'
});

And finally, requesting XML information cross-domain will cause problems. See if the API provides the information in JSONP format instead. JSON is also (slightly) easier to work with using JavaScript.

like image 20
Yi Jiang Avatar answered Sep 18 '22 06:09

Yi Jiang


I would suggest you create an array that holds the UV element IDs, suffixes and weather station ids (stationid)

var areas = [
     {id:'sydney',suffix:'syd',stationid:'YSSY'},
     {id:'melbourne',suffix:'mel',stationid:'YMML'},
     {id:'brisbane',suffix:'bri',stationid:'YBBN'},
     {id:'perth',suffix:'per',stationid:'YPPH'},
     ...
 ]

and then for the UV

// FUNCTION 1 - UV
function getUV() {

    // BEGIN AUSTRALIAN UV FUNCTION

    $.get('http://www.arpansa.gov.au/uvindex/realtime/xml/uvvalues.xml', function(d) {

        //SYDNEY UV
             $(areas).each(function(){
            var area = this;
        $(d).find('location#'+area.name).each(function(){

            var $location = $(this); 
            var uvindex = $location.find('index').text();

            var areauv = areauv += '<span>' + uvindex + '</span>' ;
            $('#uv-'+area.suffix).empty().append($(areauv)); // empty div first

            if (uvindex <= 2.0) {
                $('#risk-'+area.suffix).empty().append('Low');
                $('#curcon-'+area.suffix).empty().append('You can safely stay outdoors and use an SPF 15 moisturiser.');
            } else if (uvindex <= 5.0) {
                $('#risk-'+area.suffix).empty().append('Moderate');
                $('#curcon-'+area.suffix).empty().append('Wear protective clothing outdoors and use an SPF 15 or SPF 30 moisturiser.');
            } else if (uvindex <= 7.0) {
                $('#risk-'+area.suffix).empty().append('High');
                $('#curcon-'+area.suffix).empty().append('Wear protective clothing, limit your time outdoors and use an SPF 30 moisturiser.');
            } else if (uvindex <= 10.0) {
                $('#risk-'+area.suffix).empty().append('Very High');
                $('#curcon-'+area.suffix).empty().append('Use caution, limit exposure to the sun and use an SPF 30 moisturiser.');
            } else if (uvindex <= 20.0) {
                $('#risk-'+area.suffix).empty().append('Extreme');
                $('#curcon-'+area.suffix).empty().append('Use extreme caution, avoid exposure to the sun and use an SPF 30 moisturiser.');
            } else {
                $('#risk-'+area.suffix).empty().append('Unavailable');
                $('#curcon-'+area.suffix).empty().append('Information is currently unavailable.');
            }

        });
            });

        // END OF AUSTRALIAN UV FUNCTION

    });
}

and for the weather

function getWeather() {

        // BEGIN AUSTRALIA and NEW ZEALAND WEATHER FUNCTION
            $(areas).each(function(){
                var area = this;
        $.get('http://api.wxbug.net/getLiveCompactWeatherRSS.aspx?ACode=XXXPRIVATEXXX&stationid='+area.stationid+'&unittype=1&outputtype=1', function(d){
        $(d).find('weather').each(function(){

            var $weatherinfo = $(this); 
            var degrees = $weatherinfo.find('temp').text().replace(/\.0$/i, "");
            var conditions = $weatherinfo.find('current-condition').text();
            var icon = $weatherinfo.find('current-condition').attr('icon').replace(/\.gif$/i, ".png").split('http://deskwx.weatherbug.com/')[1];

            var temperature = temperature += '<span>' + degrees + '</span>' ;   
            $('#temp-'+area.suffix).empty().append($(temperature));

            var winformation = winformation += '<span>' + conditions + '</span>' ;
            $('#info-'+area.suffix).empty().append($(winformation));

            var wicon = wicon += '<img src="' + icon + '" alt="Weather Unavailable" />' ;
            $('#icon-'+area.suffix).empty().append($(wicon));

        });
        });
            });
}
like image 39
Gabriele Petrioli Avatar answered Sep 17 '22 06:09

Gabriele Petrioli


This should give you enough to remove a whole bunch of duplication.

var lte2 = { risk: "Low", curcon: "You can safely stay outdoors and use an SPF 15 moisturiser." },
    lte5 = { risk: "Moderate", curcon: "Wear protective clothing outdoors and use an SPF 15 or SPF 30 moisturiser." },
    lte7 = { risk: "High", curcon: "Wear protective clothing, limit your time outdoors and use an SPF 30 moisturiser." },
    uvWarningMap = {
        0: lte2,
        1: lte2,
        2: lte2,
        3: lte5,
        4: lte5,
        5: lte5,
        6: lte7,
        7: lte7
    };
like image 43
ChaosPandion Avatar answered Sep 18 '22 06:09

ChaosPandion