(譯者注:由於yeeyan編輯器對文章中的標簽做解析的原因,我在每個標簽的<符號之後都加入了一個空格,比如說,左尖括號<+head+右尖括號>,我會寫成< head>,以便其能夠在文章中正確顯示,不便之處敬請諒解。)
那麼,什麼是API呢?
應用編程接口(application program interface,API)是訪問一個軟件應用的編程指令和標准的集合。通過使用API,你就可以設計出由API提供的服務來驅動的產品。
HTML5擁有一些新的API,例如:
1. 一個與新的畫布元素一起使用的2D繪圖API,用於渲染圖形或是其他的視覺圖像
2. 一個支持離線web應用的緩存機制的API
3. 一個播放視頻和音頻的API,與新的視頻和音頻元素一起使用
4. 一個歷史記錄API,其把浏覽歷史變成可訪問的,並允許把頁面添加到這一歷史中
5. 一個和draggable屬性一起使用的拖放API
6. 一個和contenteditable屬性一起使用的編輯API
7. 鍵-值對以及內嵌的SQL數據庫的客戶端存儲,使用了JavaScript API
本篇文章重點關注兩個API:Geolocation和Web Worker,首先對這些API本身進行分析,然後創建一個包含這兩個API的頁面。
無處不在的業務:Geolocation
Geolocation API被用來確定和分享地理位置,API返回經度和緯度坐標——這是企業可用來在這一坐標附近的區域提供服務的信息,這類服務通常被稱作基於位置的服務(location-based service, LBS)。
LBS以地理數據源為參考,這些地理數據源被用來標識被監控儀器的物理位置,從而識別出與這一位置相關的人。這一功能賦予感興趣的各方與這一個人進行交互的機會,這種交互是基於一些以地理位置為中心的興趣點市場來進行的。
商業實際上是為客戶創造品質、實用性和價值,並同時為利益相關者、債權人、股東、員工和供應商創造經濟和金融利益。以地理位置為驅動力的LBS使得跟蹤和監控一個包裹或是使用了非浏覽器設備或是浏覽器的個人變得相當容易起來。從商業化的角度來說,地理位置所涉及的就是使用地理資產來確定某人或是某物所處的位置,然後把這一特定的一組信息出售給想要把這些信息用於社會、商業或是其他目的的的任何人,只要信息的擁有者的這種做法是法律許可的就可以了。
地理定位(geolocation)的工作方式
Geolocation API基於navigator這一全局對象的一個新屬性:navigator.geolocation,這一JavaScript的navigator對象提供了一些關於訪問者的浏覽器和系統的有用信息。Geolocation可以確定使用了IP地址、基於web的數據庫、無線網絡連接,以及三角定位或是GPS技術的訪問者的經度和緯度。應該要注意的一點是,由Geolocation提供的信息的准確性會基於獲取信息的手段而發生變化。偶然情況下,在一些位置上,你有可能不能獲得明確的地理位置讀數或是一點數據都接收不到。
腳本可使用navigator.geolocation對象來確定與用戶的宿主設備相關的位置信息,在檢索到位置信息之後,一個位置對象就會被創建出來,並使用這些數據做填充。
navigator.geolocation對象有三個方法:
1. getCurrentPosition()
2. watchPosition()
3. clearWatch()
getCurrentPosition()方法
getCurrentPosition()方法檢索用戶的當前位置,但只檢索一次。當該方法被腳本調用時,方法以異步的方式來嘗試獲取宿主設備的當前位置。異步通信意味著發送者和接收者並未同時地加入到這一通信過程中,使用異步通信能讓浏覽器繼續進行其他方面的活動,這樣它就無需等待來自接收實體的響應。
getCurrentPosition()方法最多可以有三個參數:
1. geolocationSuccess:帶回當前位置的回調(callback)(必需的)
2. geolocationError. 有錯誤發生時使用的回調(可選的)
3. geolocationOptions. 地理位置選項(可選的)
navigator.geolocation.getCurrentPositon()方法使用一個Position對象作為參數來把宿主設備的當前位置返回給geolocationSuccess這一回調,如果有錯誤發生的話,geolocationError回調會使用一個PositionError對象來做調用。你可以設置geolocationOptions的三個屬性:enableHighAccuracy、timeout和maximumAge,這些可選屬性相應的作用分別是啟用了高的精確性,如果設備支持這種高精確性的話;一個超時時段,這是位置應該被返回的最長等待時間;以及一個最大的時間數,緩存的位置在這一時間段內可被使用。
getCurrentPosition()方法的調用如下所示:
void navigator.geolocation.getCurrentPosition(
geolocationSuccess, geolocationError, geolocationOptions);
watchPosition()方法
watchPosition()方法定期輪詢用戶的位置,查看用戶的位置是否發生改變。其最多可帶三個參數。
當watchPosition被調用時,其異步地啟動一個查看過程,這一過程涉及了一個新的Position對象的獲取和一個watchID的創建。如果這一獲取操作是成功的,則相關的使用一個Position對象作為參數的geolocationSuccess就會被調用。在失敗時涉及的操作則是使用一個非空的geolocationError參數來調用該方法,watchPosition方法使用一個PositionError對象作為參數來生成geolocationError。當設備的位置發生改變時,一個合適的帶有新的Position對象的回調就會被調用。
watchPosition()方法的調用如下所示:
long navigator.geolocation.watchPosition(
geolocationSuccess, geolocationError, geolocationOptions);
clearWatch()方法
clearWatch()方法終止正在進行的watchPosition(),該方法只能帶一個參數。在調用時,其找到之前已經開始了的watchID參數並立即停止它。
clearWatch()方法的調用如下所示:
void navigator.geolocation.clearWatch(watchID)
Geolocation數據:Position對象
Geolocation API返回一個地理上的Position對象,該對象有兩個屬性:timestamp和coords。timestamp屬性表示地理位置數據的創建時間,coords屬性又包含七個屬性:
1. coords.latitude:估計緯度
2. coords.longitude:估計經度
3. coords.altitude:估計高度
4. coords.accuracy:所提供的以米為單位的經度和緯度估計的精確度
5. coords.altitudeAccuracy:所提供的以米為單位的高度估計的精確度
6. coords.heading: 宿主設備當前移動的角度方向,相對於正北方向順時針計算
7. coords.speed:以米每秒為單位的設備的當前對地速度
這些屬性中只有三項是保證有的:coords.latitude、coords.longitude和coords.accuracy,其余的返回null,這取決於設備的能力和其所采用的後端定位服務器。如果可能的話,heading和speed屬性可以基於用戶之前的位置計算出來。
發揮救援作用的web worker
web worker(web工作線程)補救了並發所引起的問題,web worker是HTML5家族對JavaScript的單線程問題的回答:它們在與主頁面分開的線程中運行處理過程,保留頁面以用於主要的功能,比如說維持一個穩定的UI等。
一個web worker是一個在後台加載並執行的JavaScript文件,這些worker允許你動態地加載一個JavaScript,然後使用後台的不會影響到UI的進程來執行腳本。web worker的訪問是受限的,其只允許傳遞字符串。因為web worker不使用浏覽器的UI線程,所以他們不允許訪問DOM。worker可以使用這兩個worker全局范圍的self和this引用,worker和父頁面的通信是通過使用事件模型和postMessage()方法來實現的。
因為web worker有多線程行為,因此它們只能訪問JavaScript功能的一個子集,web worker可以:
1. 訪問navigator對象
2. 使用只讀的位置對象
3. 執行XMLHttpRequest以發送HTTP或是HTTPS請求
4. 使用setTimeout()/clearTimeout()和setInterval()/clearInterval()來設置時間或是時間間隔
5. 訪問應用的緩存
6. 使用 importScripts()方法來導入外部的腳本
7. 產生其他的web worker(子worker(subworker)必需有著與主頁面一樣的來源,且必須放置於與父worker同樣的地點。)
web worker有兩種類型:專用型的worker和共享型的worker。
專用型web worker
專用型worker與創建它的腳本鏈接在一起,它可以與其他的worker或是浏覽器組件通信,但是他不能與DOM通信。
專用型worker的創建方法是把一個JavaScript文件名傳遞給一個新的worker實例,通過指定worker的執行腳本URI來使用Worker()構造函數創建一個新的worker。要創建一個專用型worker的話,輸入下面給出的代碼,這一代碼創建了一個新的專用的Worker對象:
var worker = new Worker('worker.js');
共享型web worker
共享型web worker和專用型worker一樣,不能訪問DOM,並且是受限地訪問窗體的屬性。共享型web worker只能與其他來自同一個域的共享型web worker通信,它的創建方法是把一個JavaScript名稱傳遞給一個新的共享型worker的實例來創建。
頁面腳本可以與共享型web worker通信,而然,與專用型web worker不同的是,通信是通過使用一個端口(port)對象並附加上一個消息事件處理程序來進行的。另外,在使用第一個postMessage()之前,你必須要調用端口的start()方法。
在收到web worker腳本的首個消息之後,共享型web worker把一個事件處理程序附加到激活的端口上。一般情況下,處理程序會運行自己的postMessage()方法來把一個消息返回給調用代碼,接著端口的start()方法生成一個有效的消息進程。
為了創建一個共享型web worker,你必須要創建一個SharedWorker對象而不是一個Worker對象。下面的代碼說明了如何創建一個新的SharedWorker對象:
var worker = new SharedWorker('worker.js');
構造一個包含了這兩個API的頁面
你將設計一個包含了Geolocation和Web Worker API的基本工作模式的頁面,此外,你還會用到Google Map API來渲染作為地圖收集來的數據。
頁面的組織如圖1所示,其包含了一個使用< header>< /header>標簽來創建的Header區,一個使用< section>< /section>標簽來創建的Section區,以及一個使用< aside>< /aside>標簽來創建的Aside區。
圖1. API頁面的布局
< section>和< aside>區包含了API,Section區包含了Geolocation API,Aside區包含了web worker,其用來計算素數。
在執行時,網頁的顯示如圖2所示。如果要查看地理位置數據的話,你首先必須要同意共享你的信息。web worker在頁面加載時啟動,如果你想看一看找到的素數的話,點擊Display Web Worker按鈕。
圖2. API網頁
HTML文件
HTML文件一開始的內容是清單1所示的標准的HTML5信息,< head>部分包含了一個到Google Maps API的調用,把sensor的值設置為False。使用Google Maps API對你狀態的要求是,你的應用是否在使用一個傳感器,比如說GPS來確立位置。你必須為你的Google Maps API應用聲明一個值為True或是False的sensor參數,sensor的值必須被聲明。< head>標簽還包含了到JavaScript和CSS3文件的鏈接,這些文件被用來處理網頁的功能和格式。
清單1. HTML文件開始部分的內容
< !doctype html>
< html>
< head>
< title>Basic GeoLocation Map & Web Worker Prime Number Calculator< /title>
< script src="http://maps.google.com/maps/api/js?sensor=false" kesrc="http://maps.google.com/maps/api/js?sensor=false"
type="text/javascript">< /script>
< LINK href="GeolocationWebWorker.css" kesrc="GeolocationWebWorker.css" rel="stylesheet" type="text/css">
< script src="HTML-Part3-GeolocationWebWorker.js" kesrc="HTML-Part3-GeolocationWebWorker.js" type="text/javascript">< /script>
< /head>
< body>標簽包含了onLoad事件,該事件調用地理定位的初始化函數,如清單2所示。該函數檢驗地理定位是否可在這一浏覽器中使用,這一初始化函數放在JavaScript文件中。如果浏覽器可以和Geolocation API通信的話,地圖就會被渲染。
清單2. 初始化Geolocation
< body onLoad="initGeoApp();">
< header>
< hgroup>
< h1>Geolocation & Web Worker< /h1>
< h2>Making it work< /h2>
< /hgroup>
< /header>
清單3中給出的< section>標簽包含了navigator.geolocation對象的輸出顯示信息,API返回的經度和緯度被用來創建地圖畫布,Position的coords數據也通過使用< span>< /span>標簽顯示出來。
清單3. Geolocation的地圖和位置
< section>
< p>This is the geolocation example map.< /p>
< div id="map_canvas" >< /div>
< p>This is the output from the navigator.geolocation object.< /p>
< table>
< tr>
< td>accuracy:< /td>
< td>< span id="accuracyOutput">< /span>< /td>
< /tr>
< tr>
< td>altitude:< /td>
< td>< span id="altitudeOutput">< /span>< /td>
< /tr>
< tr>
< td>altitudeAccuracy:< /td>
< td>< span id="altitudeAccuracyOutput">< /span>< /td>
< /tr>
< tr>
< td>heading:< /td>
< td>< span id="headingOutput">< /span>< /td>
< /tr>
< tr>
< td>latitude:< /td>
< td>< span id="latitudeOutput">< /span>< /td>
< /tr>
< tr>
< td>longitude:< /td>
< td>< span id="longitudeOutput">< /span>< /td>
< /tr>
< tr>
< td>speed:< /td>
< td>< span id="speedOutput">< /span>< /td>
< /tr>
< /table>
< /section>
< aside>
< p>This is the Web Worker. < /p>
< p>Prime number calculation result:
< output id="result">< /output>< /p>
Web Worker計算素數,< output>這一新的標簽被用來顯示web worker提供的計算結果,< output>標簽中的ID與JavaScript用來標識其要執行的計算的ID是相同的。在< span>和< output>標簽中用到的ID使得它們在DOM中是可訪問的,沒有引用ID的話,JavaScript就不知道要使用哪一個< span>和< output>。清單4給出了web worker的輸出。
清單4. web worker的輸出
< aside>
< p>This is the Web Worker. < /p>
< p>Prime number calculation result:
< output id="result">< /output>< /p>
< input>中用到的onClick首先顯示由素數(Prime Number)web worker計算出來的值,而第二個onClick則是被用來停止web worker的。清單5給出了代碼。在按鈕被點擊時,displayWorker()函數引發顯示web worker計算出來的結果。web worker在頁面載入後開始計算素數。
清單5. web worker的input標簽
< input type="button" value="Display Web Worker" onClick="displayWorker();">
< input type="button" value="Stop Web Worker" onClick="stopWorker();">
< /aside>
< /body>
< /html>
JavaScript文件
JavaScript是例子頁面上展示的API背後的引擎,Geolocation API是通過調用initGeoApp()函數來初始化的,這就是由< body>標簽中的onLoad()事件來執行的函數:其決定了你的浏覽器是否能夠使用地理位置數據(參見清單6)。如果你的浏覽器可以使用地理位置數據的話,則Geolocation API就會被調用。如果調用成功的話,就會使用Position中的屬性值來繪制地圖,然後屬性的值會接在地圖的後面打印出來。
清單6. Geolocation的函數
function initGeoApp()
{
if( navigator.geolocation )
{
navigator.geolocation.getCurrentPosition( success, failure);
}
else
{
alert("Your browser does not support geolocation services.");
}
}
基於你在HTML文件中提供的ID,document.getElementById被用來檢索值。document.getElementById是文檔對象的一個方法,應該通過使用document.getElementById來訪問,如清單7所示。Position的屬性值存放在這裡,這樣它們就能夠用來在要渲染的地圖下面打印屬性。
清單7. 使用getElementById來獲取coords的值
var map;
function success(position)
{
document.getElementById("accuracyOutput").innerHTML =
position.coords.accuracy;
document.getElementById("altitudeOutput").innerHTML =
position.coords.aktitude;
document.getElementById("altitudeAccuracyOutput").innerHTML =
position.coords.altitudeAccuracy;
document.getElementById("headingOutput").innerHTML =
position.coords.heading;
document.getElementById("latitudeOutput").innerHTML =
position.coords.latitude;
document.getElementById("longitudeOutput").innerHTML =
position.coords.longitude;
document.getElementById("speedOutput").innerHTML =
position.coords.speed;
接下來的這部分定義的是Google Map API的LatLng對象的坐標,如清單8所示。Google Map API LatLng對象提供了需要用來創建地圖的坐標信息,你可以設置縮放級別和其他的幾個選項,這些選項創建了呈現給用戶的地圖的外觀。
清單8. Google Map的選項
var coordinates = new google.maps.LatLng(position.coords.latitude,
position.coords.longitude);
var myOptions =
{
zoom: 14,
center: coordinates,
mapTypeControl: false,
navigationControlOptions: {style: google.maps.NavigationControlStyle.small},
mapTypeId: google.maps.MapTypeId.ROADMAP
};
注意一下mapTypeID這一選項,該選項選擇的是ROADMAP,該值所呈現的地圖的樣子如圖2所示。該選項有四個可選的值:
1. ROADMAP
2. HYBRID
3. SATELLITE
4. TERRAIN
圖3給出了選擇HYBRID選項時網頁看起來的樣子。
圖3. 使用混合式地圖的API網頁。
map_canvas這一ID被用來創建地圖,該ID是HTML文件中的< div>的ID。
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
在地圖上放一個初始位置的標記,清單9給出了這一代碼。
清單9. 放置一個初始的地圖標記
var marker = new google.maps.Marker({
position: coordinates,
map: map,
title: "You are here."
});
}
function failure()
{
alert("Sorry, could not obtain location");
}
web worker在頁面初始化之後就開始執行。如果用戶想要顯示所執行的計算的輸出的話,他/她可以點擊Display Web Worker按鈕,這將會調用displayWorker()函數。清單10給出了它的代碼。
清單10. web worker
var worker = new Worker('PrimeNumberWebWorker.js');
function displayWorker()
{
worker.onmessage = function (event)
{
document.getElementById('result').innerHTML = event.data;
};
}
如果用戶想要停止web worker的話,他/她可以點擊Stop Web Worker按鈕,這會調用清單11中給出的stopWorker()函數。
清單11. 終止worker
function stopWorker()
{
worker.terminate();
}
web worker文件
該文件是素數計算器的web worker,其計算出每個素數直到被終止執行。清單12給出了它的代碼。
清單12. 計算素數
var n = 1;
search: while (true) {
n += 1;
for (var i = 2; i <= Math.sqrt(n); i += 1)
if (n % i == 0)
continue search;
postMessage(n);
}
CSS3文件
清單13中給出的CSS3文件提供了HTML5頁面中顯示的格式。
清單13. CSS3描述
* {font-family: Arial,Helvetica,sans-serif ;
}
body {
margin: 0 300px 0 300px;
color: #990000;
background-color:#FFFFCC;
}
header > hgroup h1 {
margin: 0 0 3px 0;
padding: 0;
text-align: center;
font-size: 30px;
}
header > hgroup h2 {
margin: 0 0 15px 0;
padding: 0;
text-align: center;
font-style: italic;
font-size: 12px;
}
header p {
margin: 0 0 20px 0 ;
padding: 0;
text-align: center;
font-size: 12px;
}
aside {
width: 200px;
height: 175px;
margin: -450px 0 0 450px;
background-color: #990000;
padding: .5px 0 0 10px ;
color:#FFFFFF;
font-weight:bold;
}
div {
width: 400px;
height: 250px;
}
結論
文章系列的這一部分內容研究了Geolocation和Web Worker API的實用性。選擇這兩個API是因為把它們放在一起既說明了API使用的創新性又說明了實際上的可用性。對於HTML5規范在創建新的業務模型方面的使用來說,Geolocation是一個很好的例子。同樣,Web Worker的角色是JavaScript的並發性所固有的一些問題的解決方案。
這兩個API共同說明了一種用於商業和社會的HTML5使用模式的組合,因此,它們的功效說明了HTML5富互聯網應用的特有便利性和一般管理手段。