编者注: 此文章介绍了一组来自波特兰州立大学的学生与 Mozilla 在他们毕业设计项目中的合作成果。在过去的 6 个月中,他们与 Mozilla 的 Dietrich Ayala 合作,创建了一个 JavaScript 库,该库允许开发者优化网络操作的使用,从而节省电池寿命。该小组由 8 名拥有不同技术背景的学生组成,每个人都被分配了项目中的不同任务。恭喜该团队:
- Ryan Niebur – 团队负责人/会议主持人
- Nathan Kerr– 架构师/软件开发人员
- Tim Huynh – 记录员/电池测试员/软件开发人员
- Bin Gao– 软件开发人员
- Brianna Buckner – DevOps/软件开发人员
- Sean Mahan – 电池测试员/软件开发人员
- Scott Anecito – 文档/软件开发人员
- Casey English – 电池测试员/软件开发人员
项目概述和目标
我们的毕业设计项目旨在开发一个 JavaScript 库,使开发者更容易编写使用更少电力的应用程序,方法是减少网络请求。在新兴市场,移动设备的电池容量可能更小,信号强度可能较差,发送大量请求的应用程序会给智能手机的使用带来严重挑战。有时,为拥有强大网络基础设施的地区的用户设计的应用程序可能会对网络接入不太可靠的用户造成重大负面影响。减少电池消耗可以延长电池寿命,并为所有用户提供更好的用户体验。为了改善这种情况,我们创建了 API 来帮助开发者以最大限度地减少网络使用的方式编写移动应用程序。
为了有效解决此问题,我们为开发者提供了机制来延迟非关键请求,将请求批量处理,并检测网络条件何时最适合执行特定活动。这需要进行研究以确定各种解决方案的有效性。无论我们的 API 有效性如何,这项研究都提供了有关节省电池使用量的见解。除了我们的研究之外,我们还专注于开发者的人机工程学,希望使其对开发者易于使用。
安装和使用
库的安装非常简单:克隆 “dist” 文件夹 并选择最适合您需求的库变体。库中使用了 LocalForage 来存储每个 XMLHttpRequest (XHR) 的统计详细信息。这样,开发者可以执行分析来开发一组动态启发式方法,例如在用户最有可能成功执行 XHR 的时候使用。但是,如果您认为这不会经常使用,则可以选择无 LocalForage 版本,以获得更小的库内存占用。
我们鼓励您查看我们的 通用使用部分 和 API 使用部分 ,以全面了解使用情况和上下文。下面提供了如何使用 API 核心功能的简要概述。
关键请求
当您需要为用户立即需要的东西执行关键 XHR 时,可以使用以下语法进行操作。
AL.ajax(url [, data] [, success] [, method])
其中,url
表示端点,data 是您传递 JSON 数据的参数(例如,POST XHR),success 在请求成功完成之后调用,可选的 method 参数指定要使用的 HTTP 方法(例如,Patch、Post)。如果没有指定 method,并且 data 字段为空,则将使用 GET,但如果使用了 data,则 POST 将是默认方法。
关键请求示例如下。
AL.ajax('http://rocky-lake-3451.herokuapp.com/', {cats: 20}, function(response, status, xhr) {
console.log('Response: ', response);
console.log('Status: ', status);
console.log('Xhr: ', xhr);
});
执行此代码将产生以下输出。
Response: {"request_method":"POST","request_parameters":[]}
Status: 200
Xhr: XMLHttpRequest { readyState=4, timeout=0, withCredentials=false, ...}
非关键请求
非关键请求用于非紧急需求,它们将非关键 XHR 放入队列中,并在满足特定条件时触发。两个默认条件是“电池电量超过 10% 且刚刚执行了关键请求”或“电池电量超过 10% 且设备已插入电源”。执行非关键请求的语法与关键请求相同,区别在于函数名称和一个额外的参数 timeout。
AL.addNonCriticalRequest(url [, data] [, success] [, method] [, timeout])
timeout 的工作原理如下:给定毫秒数,如果队列没有被其他机制(例如关键请求触发)触发,则添加的 XHR(以及队列中的所有其他 XHR)将在该时间段后触发。
记录和分析
XHR 存储在 LocalForage 中。有多种函数可用于检索数据或修剪数据。通用检索语法采用以下格式,其中 callback 是一个包含与 XHR 相关对象的数组,这些对象包含与 XHR 相关的数据,例如开始时间、结束时间和请求的大小。
AL.getHistory(callback)
您可以以多种有趣的方式使用这些数据,但在基本层面上,您需要对 XHR 进行计时。通过执行以下操作,计算五个最近请求的开始时间和结束时间之间的差值。
function getRecords() {
var elem = document.getElementById('recordsList');
AL.getHistory(function (records) {
if (records) {
var counter = 0;
var string = [];
for (var i = Math.max(records.length - 5, 0); i < Math.max(records.length, 0); ++i) {
string[counter] = records[i].end - records[i].begin;
++counter;
}
elem.innerHTML = string.toString();
}
else {
console.log("Records is null");
}
});
}
研究结果
为了收集有关我们的 API 在减少电池使用方面有效性的数据,我们连接了我们的参考设备(Flame)到电池测试架,并使用我们的演示应用程序处理了 30 个不同类型的媒体请求(文本、图像和视频)。所有三个测试都在 WiFi 网络(具体来说是我们的大学 WiFi 网络)上运行。我们试图在 3G(T-Mobile)网络上运行所有三个测试,但由于连接性差,我们只能在蜂窝网络上运行文本测试。
https://www.youtube.com/watch?v=VS4txBGBoCo&feature=youtu.be
在 WiFi 上运行测试时,我们注意到 WiFi 芯片非常高效。它几乎会立即打开,并且在完成所有网络请求后,也会立即关闭。因此,我们意识到该库在 WiFi 网络上并没有太大用处;它很难比立即打开/关闭更有效。
然而,在 3G 网络上进行测试时,该库的实用性就变得非常明显。在功耗图中,有一个非常明显(且相对缓慢)的阶段,即芯片预热,其功耗逐渐增加,直到完全供电。在所有网络活动完成后,有一个更长的冷却阶段,芯片的功耗逐渐下降。很明显,将请求堆叠在一起在这样的网络类型上很有用,可以避免死区,即手机由于缺乏活动而关闭芯片,此时恰好有另一个请求进来,导致芯片以相同的缓慢速度重新供电。
总之,我们相信我们的库在手机使用 3G 网络时会很有用,并有助于节省不立即需要的请求的电池使用量。此外,可选的数据分析骨架可以帮助高级开发者为每个用户生成独特的启发式方法,以进一步减少电池消耗。

波特兰州立大学 Firefox OS 毕业设计团队:后排:Tim Huynh、Casey English、Nathan Kerr、Scott Anecito。前排:Brianna Buckner、Ryan Niebur、Sean Mahan、Bin Gao(从左到右)