DOM 트리의 탐색
DOM 트리의 순회는 트리 자료구조의 순회 방법을 따른다. 트리구조 역시 자료를 효율적으로 탐색하고, 삽입이나 삭제할 수 있는 구조로 저장하는 것을 목적으로 하는 자료구조이기 때문에 효율적인 탐색 방법이 존재한다. 트리를 효율적으로 탐색하기 위해서는 타깃 노드에 도달할 때까지 최소한의 노드들을 거쳐가야 한다. 즉, 중복으로 방문하는 노드가 없어야 하는데 이를 위해 트리를 탐색하는 과정엔 방문한 노드를 기록하는 것도 포함되어 있다.
트리 자료구조의 노드를 탐색하여, 원하는 타깃을 찾아내는 방법에는 깊이 우선 탐색과 너비 우선 탐색이 있다.
깊이 우선 탐색 방법은 루트 노드로부터 계속해서 자식 노드로 내려가며 탐색하다가 마지막 자식 노드에 도달했을 때, 만약 아직 타깃을 찾지 못했다면 다시 부모 노드로 올라가서 부모의 다른 자식 노드들을 탐색한다. 이 과정을 모든 노드를 다 방문할 때까지 반복하는 방법이다.
너비 우선 탐색 방법은 루트부터 시작해서 같은 레벨의 노드들을 왼쪽에서 오른쪽으로 탐색하고, 그 아래 레벨로 내려가서 탐색하기를 반복하는 방법이다. 트리에서 레벨이란 루트부터 어떤 노드까지 도달하는 데 지나가야 하는 간선의 개수를 뜻한다.
MDN 문서에 따르면, queryselector와 getElementByI는 깊이 우선 탐색 방법을 채택하고 있다. 깊이 우선 탐색에서는 방문 히스토리를 기록하면서 탐색해 나가고, 타깃 노드를 찾는 순간 탐색은 종료된다.
queryselector API는 해당 속성을 가진 첫 번째 노드를 찾아 반환하도록 설계되어 있어, DOM 트리는 노드를 탐색하다가 처음으로 타깃 노드가 발견되면 바로 탐색을 종료한다. 이로써 언제나 해당하는 첫 번째 노드가 리턴된다.
getElementById 를 사용하는 경우, 고유한 id를 가진 노드는 하나밖에 없기 때문에 매번 전체 트리를 탐색하지는 않는다.
브라우저를 구동하는 엔진인 웹킷에 관한 문서에 따르면, getElementById에는 해시테이블이라는 자료구조가 쓰인다. 해시테이블은 키와 값을 일대일로 매핑하여, 키가 입력되면 그에 대응되는 값을 곧바로 반환해 매우 빠른 탐색 속도를 보여준다.
즉 getElementById의 경우, 트리를 탐색하기 전에, 고유한 id에 대응하는 노드를 찾기 위해 미리 만들어져 있는 해시테이블을 우선적으로 탐색한다. 그리고 찾는 id에 대응되는 노드를 발견하면 빠르게 반환하고, 찾지 못했다면 깊이 우선 탐색으로 노드를 찾는다.
queryselector 와 getElementById API는 모두 웹페이지 상의 특정 태그에 접근하기 위해 사용할 수 있는 메서드이고, 깊이 우선 탐색 방식으로 탐색을 수행한다. 깊이 우선 탐색의 시간 복잡도는 최악의 경우 모든 정점을 방문해야 하므로 결코 빠르다고 할 수 없다.
다만, 시간만 고려한다면 해시테이블을 사용하는 getElementById 가 queryselector보다 훨씬 좋은 메서드라고 할 수 있다.
하지만 탐색 속도는 getElementById가 더 빠를지라도, queryselector를 이용하면 여러 가지 속성들을 자유롭게 활용하고, 노드를 탐색할 수 있어서 유연하기 때문에 메서드 확장성 면에서 장점이다. 따라서 이 두 메서드는 목적에 맞게 활용하는 것이 좋다.