loadDeals 函数
var deals = [];
var sections = [];
var dealDetails = {};
var dealsUrl = "http://deals.ebay.com/feeds/xml";
function loadDeals(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
var i = 0;
var j = 0;
var dealsXml = this.responseXML.firstChild;
var childNode = {};
for (i=0; i< dealsXml.childNodes.length;i++){
childNode = dealsXml.childNodes.item(i);
switch(childNode.localName){
case 'Item':
deals.push(parseDeal(childNode));
break;
case "MoreDeals":
for (j=0;j
清单 4 展示了 loadDeals 函数,以及应用程序中使用的全局变量。您使用了一个 deals 数组和一个 sections 数组。它们是相关交易的附加组(例如,Deals under $10)。还有一个名为 dealDetails 的映射,其键是 Item IDs(来自于交易数据),其值是从 eBay Shopping API 获取的详细信息。
您首先调用一个代理,该代理又将调用 eBay Daily Deals REST API。这将把交易列表作为一个 XML 文档提供给您。您解析用于进行 Ajax 调用的 XMLHttpRequest 对象的 onreadystatechange 函数中的文档。您还使用其他两个函数,parseDeal 和 parseSection,来将 XML 节点解析为更易于使用的 JavaScript 对象,但由于它们只是令人厌烦的 XML 解析函数,因此我在这里没有包括它们。最后,在解析了 XML 后,您还使用了另外两个函数,createDealUi 和 createSectionUi,来修改 DOM。此时,这个 UI 如 图 1 所示。
如果您返回 清单 4,就会注意到在加载主交易之后,您对这些交易的每个部分都调用了 loadDetails 函数。在这个函数中,您通过使用 eBay Shopping API 加载每个交易的附加细节 — 但前提是浏览器支持 Web Workers。清单 5 展示了 loadDetails 函数。
清单 5. 预取交易细节
function loadDetails(items){
if (!!window.Worker){
items.forEach(function(item){
var xmlStr = null;
if (window.localStorage){
xmlStr = localStorage.getItem(item.itemId);
}
if (xmlStr){
var itemDetails = parseFromXml(xmlStr);
dealDetails[itemDetails.id] = itemDetails;
} else {
var worker = new Worker("details.js");
worker.onmessage = function(message){
var responseXmlStr =message.data.responseXml;
var itemDetails=parseFromXml(responseXmlStr);
if (window.localStorage){
localStorage.setItem(
itemDetails.id, responseXmlStr);
}
dealDetails[itemDetails.id] = itemDetails;
};
worker.postMessage(item.itemId);
}
});
}
}
在 loadDetails 中,您首先检查全局作用域(window 对象)中的 Worker 函数。如果该函数不在那里,那么无需做任何事。反之,您首先检查 XML 的 localStorage 以获取这个交易的细节。这是移动 Web 应用程序常用的本地缓存策略,本系列第 2 部分.详细介绍过这种策略。
如果 XML 位于本地,那么您在 parseFromXml 函数中解析它并将交易细节添加到 dealDetails 对象。反之,则衍生一个 Web Worker 并使用 postMessage 向其发送 Item ID。当这个 Worker 检索到数据并将数据发布回主线程后,您解析 XML,将结果添加到 dealDetails,然后将 XML 存储到 localStorage 中。清单 6 展示了这个 Worker 脚本:details.js。
清单 6. 交易细节 Worker 脚本
importScripts("common.js");
onmessage = function(message){
var itemId = message.data;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
postMessage({responseXml: this.responseText});
}
};
var urlStr = generateUrl(itemId);
xhr.open("GET", "proxy?url=" + escape(urlStr));
xhr.send(null);
}
这个 Worker 脚本非常简单。您使用 Ajax 调用代理,该代理又调用 eBay Shopping API。当您收到来自代理的 XML
后,使用一个 JavaScript 对象文字(object literal)将其发送回主线程。注意,即使您能够使用来自一个 Worker 的 XMLHttpRequest,但所有信息都将返回它的 responseText 属性,而不是它的 responseXml 属性。这是因为这个 Worker 脚本范围内没有 JavaScript DOM 解析器。注意,generateUrl 函数来自 common.js 文件(见 清单 7)。您使用 importScripts 函数导入 common.js 文件。
清单 7. Worker 导入的脚本
function generateUrl(itemId){
var appId = "YOUR APP ID GOES HERE";
return "http://open.api.ebay.com/shopping?callname=GetSingleItem&"+
"responseencoding=XML&appid=" + appId + "&siteid=0&version=665"
+"&ItemID=" + itemId;
}
现在,您已经知道如何(为支持 Web Workers 的浏览器)填充交易细节,我们返回 图 1 研究一下如何在应用程序中使用这种方法。注意,每笔交易旁边都有一个 Show Details 按钮,单击该按钮修改这个 UI,如 图 2 所示。
图 2. 显示的交易细节
这个 UI 将在您调用 showDetails 函数时显示。清单 8 展示了这个函数。
清单 8. showDetails 函数
function showDetails(id){
var el = $(id);
if (el.style.display == "block"){
el.style.display = "none";
} else {
el.style.display = "block";
if (!el.innerHTML){
var details = dealDetails[id];
if (details){
var ui = createDetailUi(details);
el.appendChild(ui);
} else {
var itemId = id;
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 &&
this.status == 200){
var itemDetails =
parseFromXml(this.responseText);
if (window.localStorage){
localStorage.setItem(
itemDetails.id,

