Posts Tagged ‘Javascript’

HTML5學習筆記

Wednesday, November 24th, 2010

以下內容是根據讀完”Professional JavaScript for Web Developers 2nd Edition“這本書的心得而來。

持續更新中…

querySelector() & querySelectorAll()
提供像CSS selector一般的方式來取得element物件,jQuery framework已經改以這兩個method來實作取得element的方法。速度上比自己用JavaScript去寫一個CSS selector parser快很多。

// get first element with a class of 'selected'
var elm = document.querySelector('.selected');

// get all <strong> elements inside of <p> elements
var elmList = document.querySelectorAll('p strong');
classList property
存在於element,可用來對element做class屬性的操作。有add, remove, has, toggle四個methods。
// add 'selected' class name
elm.classList.add('selected');

// remove 'selected' class name
elm.classList.remove('selected');

// check the element has 'selected' class name?
if( elm.classList.has('selected') ) {
    // do something...
}

// switch the 'selected' class name on target element when user click trigger button (if target element has the class name then remove it, otherwise, add it)
$('triggerBtn').click(function() {
    elm.classList.toggle('selected');
});
postMessage()
可用來做Cross-Document(iframe)之間的溝通。在HTML4,兩個不同的document之間是完全無法做溝通的。而HTML5提供了這個比較安全的做法,來達到資料交換的目的。來源document可以call這個method代入要傳送的資料及來源domain、port資訊等等。而接收方document會收到一個”message” event,可根據來源資訊來決定。

<iframe id="inner_page" src="http://test.domain/inner.html"></iframe>
// in main page
var innerWin = document.getElementById('inner_page').contentWindow;

// send a message, parameters: data, origin
innerWin.postMessage('Thank you!', 'http://test.doamin');
// in inner.html
EventUtil.addHandler(document, 'message', function(event) {
    if( event.origin.indexOf('test.domain') >= 0 ) {
        // display the data
        alert(event.data);

        // send a message back
        event.source.postMessage('You are welcome!', 'http://test.domain');
    }
});
<video> & <audio>
用來做影片、音樂的播放。提供許多property及event可對影片及音樂播放做細微控制。

<!-- embed a video -->
<video src="movie.mpg" id="myVideo">Video player not available</video>

<!-- embed a audio -->
<audio src="song.mp3" id="myAudio">Audio player not available</audio>
<canvas>
可用來在Web Page上繪圖,包括fillRect, lineTo, fillText, drawImage…etc.等。目前除了IE外,其他Browser均有支援。詳見這裡
offline & online event
HTML5新增了offline和online兩個event,可以用來偵測目前的網路連線狀態,而對使用者做不同的UI回應。開發者可以access navigator.online這個boolean值用來做判斷,true代表連線中,false代表連線失敗。

EventUtil.addHandler(window, 'offline', function() {
    // some codes to handle offline status
});

EventUtil.addHandler(window, 'online', function() {
    // some codes to handle online status
});

// make different response by online stauts when user click a trigger button
$('triggerBtn').click(function() {
    if( navigator.online ) {
        // do something...
    } else {
        alert('The connection is lost, please check your network status.');
    }
});
pushState()
這個method可以讓一個AJAX Web Application在某一個時間點塞入一個state object到history queue裡,讓使用者也可以按Back返回鍵回到上一步的狀態。

// add state to history stack
history.pushState({mode: 'edit'}, 'Editing');

// listen for a chance in state
EventUtil.addHandler(window, 'popstate', function(event) {
    var state = event.state;

    if( mode == 'edit' ) {
        // restore page to 'edit' state
    }
});
Database Storage
HTML5提供了client端的database空間讓JavaScript code可自由存取使用,Web App因此可以做出更接近OS Native App般更豐富的功能。

// create database
var db = window.openDatabase('TestDB', '1.0', 'My Test Database', 200000);
// create table
db.transcation(function(tract) {
    var queryStr = 'CREATE TABLE Messages (id REAL UNIQUE, msg TEXT)';
    // parameters: query string, query parameter, success callback, fail callback
    tract.executeSql(queryStr, [],
        function(tract, results) {
            // table create successfully, do something...
        }, function(tract, error) {
            // table create failed, do something...
        }
    );
});
// query data
db.transcation(function(tract) {
    var queryStr = 'SELECT id, msg FROM Messages WHERE id=? and msg=?';
    // parameters: query string, query parameter, success callback, fail callback
    tract.executeSql(queryStr, [queryId, queryMsg],
        function(tract, results) {
            for( var i=0; i<results.rows.length; i++ ) {
                var row = results.rows.item(i);
                alert(row.id + '=' + row.msg);
            }
        }, function(tract, error) {
            alert('the query cannot be done!');
        }
    );
});
Drag & Drop
HTML5提供預設的drag and drop UI支援,所有的element均有一個draggable屬性來決定是否可被拖曳。而image, text和link這三種element的預設draggable值為true,其他為false,也可以手動去更改這個屬性值。而要被drop的element可以去監聽event: dragenter, dragover, dragleave, drop。也可以設定或取得event裡的dataTransfer object資料,和指定其dropEffect及effectAllowed兩個屬性。
var dropElm = document.getElementById('my_drop_panel');

// listen dragenter
EventUtil.addHandler(dropElm, 'dragenter', function(event) {
    // do something...
});
WebSocket
可以在Browser和Server之間打開一條Socket通道,做即時的資料傳輸。用以取代類似像Comet的技術。某些應用如: WebIM, 即時股票指數更新…等,就可以改用這個方式來實現。

// create socket connection
var socket = new WebSocket('ws://test.domain/connect/');

// listen connection status as opened
socket.onopen = function(event) {
    alert('Connection is ready');
};

// listen connection status as closed
socket .onclose = function(event) {
    alert('Connection is closed');
};

// receive data from server
socket.onmessage = function() {
    var data = event.data;
    // do something...
};

// send data to server
socket.send('fp=1');

使用DocumentFragment來加快DOM操作速度

Thursday, November 18th, 2010

DocumentFragment這個物件,一般人好像很少用到。這是一個可以大幅增進Web Page效能物件。廢話不多說,用法如下,假如你有一段code要插入數個element到body裡:

原本的寫法

	for( var i=0; i<100; i++ ) {
		var item = document.createElement('div');
		$(item).text('Element-'+i);
		$(item).css({
			background: 'gold',
			padding: 5,
			margin: 5,
			float: 'left'
		});
		$('body').append(item);
	}

使用DocumentFragment的新寫法

	var fragment = document.createDocumentFragment();
	for( var i=0; i<100; i++ ) {
		var item = document.createElement('div');
		$(item).text('Element-'+i);
		$(item).css({
			background: 'gold',
			padding: 5,
			margin: 5,
			float: 'left'
		});
		fragment.appendChild(item);
	}
	$('body').append(fragment);

用Firefox實測,使用第二種DocumentFragment寫法,速度快了將近一倍 ;-)

之所以用DocumentFragment速度會變快的原因是,DocumentFragment是一個頁面上”不存在“的element物件。所以你對它做任何操作都不會影響到使用者觀看的外觀。第一段code寫法,其實對browser做了100次”更新頁面”的動作,而第二段code只對browser更新一次頁面。這樣說知道速度差在哪了吧…。

另外,當DocumentFragment被插入頁面時,只有它的child element會被加入頁面,它”本身”並不會被加入。

不過,上面兩段code做的事,還可以用下面這段code取代,速度比第二段code更快一倍。做法就是把全部要被插入element的HTML字串組成一個大字串,再一次寫入。但不是每個程式邏輯都適合用這種寫法,例如說如果想要在每個item element被create之後,另外綁定一個callback function或執行某個jQuery plugin的初始化,下面這種寫法就辦不到了。

	var html = '';
	for( var i=0; i<100; i++ ) {
		html += '<div style="background:gold; padding:5px; margin:5px; float:left;">Element-'+i+'</div>';
	}
	$('body').append(html);

神奇的Duff’s Device演算法

Thursday, November 18th, 2010

這是在看“Professional JavaScript for Web Developers 2nd Edition”這本書時看到的。

這個演算法的目的是為了降低一般for/while迴圈初始時的額外資源和一直去check condition所造成的額外運算,而改成每次”直接”執行8次要做的process流程。Tradeoff是code會寫比較多。較適用於資料量龐大的Array,若是小資料則沒有使用的必要。以下範例code以JavaScript為例。

原本的code

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

改良版的Duff’s Device code

// calculate the values
var iterations = Math.floor(values.length / 8);
var leftover = values % 8;
var i = 0;

// execute the remain values
if( leftover > 0 ) {
	do {
		process(values[i++]);
	} while (--leftover > 0 );
}

// execute values 8 times per loop
do {
	process(values[i++]);
	process(values[i++]);
	process(values[i++]);
	process(values[i++]);
	process(values[i++]);
	process(values[i++]);
	process(values[i++]);
	process(values[i++]);
} while(--iterations > 0);

不過經過我實際測試的結果,好像沒什麼差… :???:

相關的參考文章:
http://en.wikipedia.org/wiki/Duff’s_device