[요약] High Performance Javascript

전역 변수에 대한 접근은 모든 브라우저에서 느려진다.


function initUI() {
    var bd = document.body;
    var links = document.getElementsByTagName("a");
    var i = 0;
    var len = links.length;

    while (i < len) {
        update(links[i++]);
    }

    document.getElementById('go-btn').onclick = function() {
        start();
    };

    bd.className = 'active';
}

위의 예제에서는 document 객체를 3번이나 참조하므로 느려진다.
그렇기 때문에 전역변수를 로컬 변수로 변환해서 사용하면 성능이 향상된다.

// 변경 로직
function initUI() {
    var doc = document;
    var bd = doc.body;
    var links = doc.getElementsByTagName("a");
    var i = 0;
    var len = links.length;

    while (i < len) {
        update(links[i++]);
    }

    doc.getElementById('go-btn').onclick = function() {
        start();
    };

    bd.className = 'active';
}

클로저를 사용할 때는 항상 주의를 해야 한다.

동적 코드를 생성하는 eval() 함수의 사용은 자제 하는게 좋다.

멤버가 깊이 중첩될수록 데이터 접근이 더 느려진다.

windows.location.href.toString() 보다 window.location.href 를 더 빨리 해석한다.

// Bad
window.location.href

// good
location.href

DOM이 하나의 대륙이고 자바스크립트가 다른 대륙인데, 두 대륙을 아주 긴 다리로 연결했다고 생각하면 이해하기 쉽다.

아래의 로직은 innerHTML 값을 읽기 위해 한번 접근하고 그 값을 수정하기 위해 한번 더 DOM 에 접근한다.

// Bad
function innerHTMLLoop() {
    for (var count = 0; count < 15000; count++) {
        document.getElementById('here').innerHTML += 'a';
    }
}

// Good
function innerHTMLLoop() {
    var content = '';
    for (var count=0; count < 15000; count++) {
        content += 'a';
    }

    document.getElementById('here').innerHTML += content;
}

예기치 못한 무한루프

  • document.getElementsByName()
  • document.getElementsByClassName()
  • document.getElementsByTagName()

HTMLCollection 객체에 접근하는 함수는 호출 될 때 마다 DOM 모델에서 모든 객체를 대상으로 하므로 아래의 코드는 무한 루프에 빠진다.

var allDivs = document.getElementsByTagName('div');
for (var i=0; i<allDivs.length; i++) {
    document.body.appendChild(document.createElement('div'));
}

아래의 코드는 HTMLCollection이 아니므로 반환된 노드는 문서 구조를 동적으로 변경하지 않는다.

var elements = document.querySelectorAll('#menu a');

알고리즘

  • for 문
  • while 문
  • do while문
  • for-in 문

위의 4가지 반복문중에서 for-in 문의 성능이 가장 낮다. 객체에 많은 속성이 포함되어 있다면 for-in 문은 사용을 자제해야 한다.

루프의 순서

일반적인 프로그래밍 언어에서는 루프의 순서를 거꾸로 하기만 해도 성능이 향상된다.
실행 조건을 평가 할 때 단순히 0과 비교.

for (var i=0; i<items.length; i++) {
    process(items[i]);
}

// Better

for (var i=items.length; i > 0; i--) {
    process(items[i])
}

조건문

  • if-else
  • switch

조건이 적을 때는 if-else 구문을 사용하고 조건이 많은 경우에는 switch 구문을 사용한다. if-else 구문은 조건이 많아 질 수록 느려진다.

if-else 구문을 사용할 때도 자주 발생하는 조건을 우선적으로 적으면 성능이 향상된다.

문자열과 정규 표현식

정규 표현식의 효율성을 올리는 방법

  1. 실패할 거라면 되도록 일찍 실패하게
  2. 단순하고 꼭 필요한 토큰으로 시작
  3. or 연산자를 줄이고, 써야 한다면 적용 범위를 작게
  4. 정규식을 뼌수에 할당해서 재사용
  5. 복잡한 정규식을 간단한 조각으로 분리

응답성 좋은 인터페이스

  • 자바스크립트 코드가 100밀리초 이상으로 실행되서는 안된다.
  • 오래 걸리는 작업을 타이머로 분리해서 실행한다.
  • 큰 JSON 문자열의 파싱 작업은 web worker 를 이용해서 별도로 처리하도록 한다.

[Javascript] How to Become a Great JavaScript Developer

번역 사이트

자바스크립트도 굉장히 매력적인 언어라 공부할 수 있는 방법을 정리해봤습니다.

[요점정리]

1. 책읽기

  • JavaScript: The Good Parts by Douglas Crockford
  • JavaScript: The Definitive Guide, 6th Edition be David Flanagan
  • Secrets of the JavaScript Ninja by John Resig’s

2. 라이브러리 배우기, 사용하기, 읽기

  • jQuery
  • Backbone (recommended)
  • Underscore

3. 연습하고, 스스로에게 질문하기

  • Closures
  • Prototypes
  • Array Extras(Map, Filter)
  • Prototype을 사용한 상속은 어떻게 동작하는가?
  • Closure의 정의는 무엇인가?
  • this 키워드 의미는 어떻게 변하는가?
  • apply/bind/map/filter/call은 어떻게 사용하는가?

[질문]

"bind를 두번 썼을 때, `this`는 무엇을 의미하는가? 어떻게 jQuery는 `this` 키워드를 전역 object가 아닌 jQuery Object로 만드는가?

4. 표준 배우기

5. 웹에 있는 자료 활용

[Javascript] 반복문과 Array.pop() , shift() 시 주의점

Javascript로 만드는 간단한 프로그램 작성중에 당혹스럽게 만들었던 부분이 있어 공유합니다.

Java에서 사용할때는 전혀 생각지도 않았던 것이 문제가 발생되네요..

지금 생각해보면 Java에서는 ConcurrentModificationException이 발생되었었네요.

일단 아래의 코드를 보겠습니다.

    function test() {
        var array = ["1", "2", "3", "4", "5"];
        console.log("===========Index를 활용한 반복문==========")
        for(var i=0; i<array.length; i++) {
            console.log(array[i]);
        }


        console.log("===========Array.pop() 을 사용한 반복분============");
        array = ["1", "2", "3", "4", "5"];
        for(var i=0; i<array.length; i++) {
            console.log(array.pop());
        }

        console.log("==========선언부분에 길이 설정=============");
        array = ["1", "2", "3", "4", "5"];
        for(var i= 0, len=array.length; i<len; i++) {
            console.log(array.pop());
        }


        console.log("===========Enhanced For 반복문에 Array.pop() 사용=============");
        array = ["1", "2", "3", "4", "5"];
        for(var i in array) {
            console.log(array.pop());
        }
        console.log("==========================================")
    }

코드는 설명 부분이 필요 없을 정도로 간단합니다.

단지 차이가 있다면 선언부에 길이를 설정하는가 아니면 Java에서 말하는 Enhanced for를 사용해서 처리하느냐의 문제 입니다.

위의 코드를 실행하면 아래와 같은 결과를 얻습니다.

"===========Index를 활용한 반복문=========="
"1"
"2"
"3"
"4"
"5"
"===========Array.pop() 을 사용한 반복분============"
"5"
"4"
"3"
"==========선언부분에 길이 설정============="
"5"
"4"
"3"
"2"
"1"
"===========Enhanced For 반복문에 Array.pop() 사용============="
"5"
"4"
"3"
"=========================================="

정리하면 pop() 이나 shift() 를 사용하게 되면 배열에서 해당 정보가 빠지기 때문에 원하는 만큼 반복문이 실행되지 않습니다.

[Chrome App] TCP 소켓 연결 블럭

HTML5 기반의 Chrome APP 을 만들려고 하는데 실시간으로 데이터를 주고 받아야 하는 이슈가 있어
Chrome API 에 나와 있는 Network Communication 내용과 Chrome App Sample 의 Telnet 예제를 보고 테스트중…

TcpClient.prototype._onCreate = function(createInfo) {
	this.socketId = createInfo.socketId;
	if (this.socketId > 0) {
		socket.connect(this.socketId, this.host, this.port, this._onConnectComplete.bind(this));
		this.isConnected = true;
	} else {
		error('Unable to create socket');
	}

};

위의 내용중 socket.connect 함수 부분에 BLOCK이 되고 더 이상 진행이 안되는 문제가 발생됨.

예제 소스

var host = document.getElementById('host').value;
var port = parseInt(document.getElementById('port').value, 10);
connect(host, port);

테스트 소스

var host = document.getElementById('host').value;
var port = document.getElementById('port').value;
connect(host, realPort);

소스의 차이는 보면 알 수 있지만 connect 라는 함수의 인자는 Host(String), Port(Integer) 를 넘겨줘야 하는데
테스트 소스는 Port(String) 타입으로 전달해서 문제가 발생된 내용이다.
Javascript의 type 이 없는 부분에 대한 어려움을 이번에 깨달음.