使用 W3C Performance 对象通过 R 和 JavaScript 将浏览器内的性能数据可视化[转]
当考虑 Web 性能指标时,需要关注的目标数字应该是从您自己的用户那里获得的实际用户指标。最常见的方法是利用 Splunk 之类的工具来分析您的机器数据,该工具支持您分析和可视化您的访问权限和错误日志。利用这些工具,您可以收集某些方面的性能数据,比如读取资产的文件 I/O 时间,以及 API 请求的访问时间。但是,您仍然需要推断客户端性能数据,将信号调用方在某些高级的检查点上,或者只利用类似 WebPagetest 的工具运行综合测试。现在,W3C 已将 API 标准化,用户可以通过使用 Performance
对象(该对象对于所有现代浏览器中的 Windows 对象而言是一个本机对象)捕获并报告浏览器内的性能数据。
捕获并报告浏览器内性能数据的 API
在 2010 年年末,万维网联盟 (W3C) 建立了一个新的工作组,即 Web 性能工作组,该工作组提供了用来测量用户代理特性和 API 的应用程序性能的各个方面的方法。该小组还开发了一个支持将浏览器暴露给 JavaScript 的 API,这是一个关键的 Web 性能指标。
在这个 API 中,该工作组创建了大量的新对象和事件,可量化性能指标和优化性能。总的说来,这些对象和界面包括:
Performance
对象:暴露多个对象,比如PerformanceNavigation
、PerformanceTiming
和MemoryInfo
,并能记录高精度时间(high resolution time),从而获得亚毫秒级计时。Page Visibility
API:使您能够确定某个给定页面是可见的还是隐藏的,从而能够优化动画的内存使用,或优化用于轮询操作的网络资源。
使用这些对象和界面捕获浏览器内的性能指标并将它们可视化。
Performance 对象
如果在 JavaScript 控制台中键入 window.performance
,则会返回一个类型为 Performance
的对象,以及该对象所暴露的一些对象和方法。目前,标准的对象集包含:
window.performance.timing
用于类型PerformanceTiming
window.performance.navigation
用于类型PerformanceNavigation
window.performance.memory
用于类型MemoryInfo
(仅适用于 Chrome 浏览器)
图 1 显示了 Performance
对象的屏幕截图,可展开该对象来显示 PerformanceTiming
对象及其属性。
图 1. Performance
对象
Performance
对象被显示在控制台中,随它一起显示的还有展开的 PerformanceTiming
对象。
PerformanceTiming
对象
PerformanceTiming
对象是以公共属性的形式暴露的,在浏览器中执行检索和呈现内容的步骤中,它是一个关键指标。表 1 显示了与PerformanceTiming
对象中的每一个属性相对应的描述。
表 1. PerformanceTiming
对象属性
对象属性 | 描述 |
---|---|
navigationStart |
在导航开始的时候、在浏览器开始卸载前一页(如果有这样的页面)的时候,或者在开始提取内容的时候,捕获所需的数据。它将包含 unloadEventStart 数据或 fetchStart 数据。要想跟踪端到端的时间,可从使用这个值开始。 |
unloadEventStart / unloadEventEnd |
在浏览器开始卸载前一页或已完成前一页的卸载的时候,捕获所需的数据(如果相同域中有前一页需要卸载的话)。 |
domainLookupStart / domainLookupEnd |
在浏览器开始和完成针对所请求内容的 DNS 查找时,捕获所需的数据。 |
redirectStart /redirectEnd |
在浏览器开始和完成任何 HTTP 重定向时捕获所需的数据。 |
connectStart /connectEnd |
在浏览器开始和完成建立当前页面的远程服务器 TCP 连接时捕获所需的数据。 |
fetchStart |
在浏览器首次开始检查用于所请求资源的缓存时捕获所需的数据。 |
requestStart |
在浏览器通过发送 HTTP 请求来获得所请求的资源时捕获所需的数据。 |
responseStart /responseEnd |
在浏览器首次进行注册并完成注册收到服务器响应时捕获所需的数据。 |
domLoading /domComplete |
在文档开始和完成加载时捕获所需的数据。 |
domContentLoadedEventEnd /domContentLoadedEventStart |
在文档的 DOMContentLoaded 开始和完成加载时捕获所需的数据,这相当于浏览器已完成所有内容的加载并运行页面中包含的所有脚本。 |
domInteractive |
在页面的 Document.readyState 属性变为 interactive 时捕获所需的数据,这会导致触发 readystatechange 事件。 |
loadEventStart /loadEventEnd |
在加载事件触发前和加载事件触发后立刻捕获所需的数据。 |
要想将上述步骤及其相应内容的顺序更好地可视化,请参见图 2。
图 2. 可视化 PerformanceTiming
属性的顺序
Performance 导航
图 3 显示了包含已展开的 PerformanceNavigation
对象的 Performance
对象。
图 3. PerformanceNavigation
对象
请注意,导航对象有两个只读属性:redirectCount
和 type
。顾名思义,redirectCount
属性是 HTTP 重定向的数量,浏览器根据它们来获取当前页面。
HTTP 重定向是 Web 性能的一个重要因素,因为它们会导致每一次重定向都需要执行一次完整的 HTTP 往返过程。原始请求是从 Web 服务器返回的,作为包含新位置路径的 301 或 302。然后,浏览器必须初始化一个新的 TCP 连接,并发送一个新请求来获得新位置。这一附加步骤为原始资源请求增加了额外的延迟。
redirectCount
属性如清单 1 所示。
清单 1. 访问 redirectCount
属性
>>> performance.navigation.redirectCount
0
导航对象的另一个属性是 type
。navigation.type
属性是用下列常量表示的 4 个值中的一个:
TYPE_NAVIGATE
的值为 0,表示可通过单击一个链接、提交表单或直接在地址栏中输入 URL 导航到当前页面。TYPE_RELOAD
的值为 1,表示通过重载操作到达当前页面。TYPE_BACK_FORWARD
的值为 2,表示通过使用浏览器历史记录、使用 back 或 forward 按钮、以编程方式,或者通过浏览器的历史对象来导航到页面。TYPE_RESERVED
的值为 255,它是其他任何导航类型的全方位指示。
信息汇总
要想使用这些对象来捕获和可视化客户端性能指标,可先创建一个 JavaScript 库,收集 PerformanceTiming
数据,并将这些数据发送到某个端点进行收集和分析。查看这个 JavaScript 库,该库恰好用于完成这项工作。
perfLogger.js 脚本使用了 Performance
对象。创建一个名为 perfLogger
的命名空间,并声明一些局部变量来保存根据 PerformanceTiming
属性推测的值。
您可以通过使用这些示例和下面这些模式来计算时间:
- 要计算认知时间(perceived time) — 从
timing.navigationStart
中减去当前时间。 - 要计算到达页面过程中所经历的所有重定向时间 — 从
timing.redirectStart
中减去timing.redirectEnd
。 - 要想获得执行 DNS 查找所用的时间 — 从
timing.domainLookupStart
中减去timing.domainLookupEnd
,要想获得呈现页面所用的时间,请从xs
中减去当前时间。
声明并初始化局部变量后,使用 public getter 函数从命名空间暴露它们,如清单 2 所示。
清单 2. 暴露 public getter
函数的局部变量
var perfLogger = function(){
var serverLogURL = "/lib/savePerfData.php",
loggerPool = [],
_pTime = Date.now() - performance.timing
.navigationStart || 0,
_redirTime = performance.timing.redirectEnd
- performance.timing.redirectStart || 0,
_cacheTime = performance.timing.domainLookupStart
- performance.timing.fetchStart || 0,
_dnsTime = performance.timing.domainLookupEnd
- performance.timing.domainLookupStart || 0,
_tcpTime = performance.timing.connectEnd
- performance.timing.connectStart || 0,
_roundtripTime = performance.timing.responseEnd
- performance.timing.connectStart || 0,
_renderTime = Date.now() - performance.timing
.domLoading || 0; //expose derived performance data
perceivedTime: function(){
return _pTime;
},
redirectTime: function(){
_redirTime;
},
cacheTime: function(){
return _cacheTime;
},
dnsLookupTime: function(){
return _dnsTime;
},
tcpConnectionTime: function(){
return _tcpTime;
},
roundTripTime: function(){
return _roundtripTime;
},
pageRenderTime: function(){
return _renderTime;
}, }
您可以从命名空间访问属性,如清单 3 所示。
清单 3. 从命名空间访问属性
perfLogger.pageRenderTime
perfLogger. roundTripTime
perfLogger. tcpConnectionTime
perfLogger. dnsLookupTime
perfLogger. cacheTime
perfLogger. redirectTime
perfLogger. perceivedTime
在命名空间中,函数 logToServer
将指标重新写回您在变量 serverLogURL
中定义的端点,如清单 4 所示。
清单 4. logToServer
函数
function logToServer(id){
var params = "data=" + JSON.stringify(jsonConcat
(loggerPool[id],TestResults.prototype));
console.log(params)
var xhr = new XMLHttpRequest();
xhr.open("POST", serverLogURL, true);
xhr.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xhr.setRequestHeader("Content-length", params.length);
xhr.setRequestHeader("Connection", "close");
xhr.onreadystatechange = function()
{
if (xhr.readyState==4 && xhr.status==200)
{
console.log('log written');
}
};
xhr.send(params);
}
perfLogger.js 库还提供了一些基准测试功能,您可以在其中测试 JavaScript 的专用数据块,甚至可以运行一组花费 N 时间量的测试来执行真正的基准测试。
perfLogger.js 库的完整源代码如清单 5 所示。
清单 5. perfLogger.js 库的完整源代码
var perfLogger = function(){
var serverLogURL = "/lib/savePerfData.php",
loggerPool = [],
_pTime = Date.now() - performance.timing.navigationStart
|| 0,
_redirTime = performance.timing.redirectEnd
- performance.timing.redirectStart || 0,
_cacheTime = performance.timing.domainLookupStart
- performance.timing.fetchStart || 0,
_dnsTime = performance.timing.domainLookupEnd
- performance.timing.domainLookupStart || 0,
_tcpTime = performance.timing.connectEnd
- performance.timing.connectStart || 0,
_roundtripTime = performance.timing.responseEnd
- performance.timing.connectStart || 0,
_renderTime = Date.now() - performance.timing.domLoading
|| 0; function TestResults(){};
TestResults.prototype.perceivedTime = _pTime;
TestResults.prototype.redirectTime = _redirTime;
TestResults.prototype.cacheTime = _cacheTime;
TestResults.prototype.dnsLookupTime = _dnsTime;
TestResults.prototype.tcpConnectionTime = _tcpTime;
TestResults.prototype.roundTripTime = _roundtripTime;
TestResults.prototype.pageRenderTime = _renderTime; function jsonConcat(object1, object2) {
for (var key in object2) {
object1[key] = object2[key];
}
return object1;
} function calculateResults(id){
loggerPool[id].runtime = loggerPool[id].stopTime
- loggerPool[id].startTime;
} function setResultsMetaData(id){
loggerPool[id].url = window.location.href;
loggerPool[id].useragent = navigator.userAgent;
} function drawToDebugScreen(id){
var debug = document.getElementById("debug")
var output = formatDebugInfo(id)
if(!debug){
var divTag = document.createElement("div");
divTag.id = "debug";
divTag.innerHTML = output
document.body.appendChild(divTag);
}else{
debug.innerHTML += output
}
} function logToServer(id){
var params = "data=" + JSON.stringify(jsonConcat(
loggerPool[id],TestResults.prototype));
console.log(params)
var xhr = new XMLHttpRequest();
xhr.open("POST", serverLogURL, true);
xhr.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xhr.setRequestHeader("Content-length", params.length);
xhr.setRequestHeader("Connection", "close");
xhr.onreadystatechange = function()
{
if (xhr.readyState==4 && xhr.status==200)
{
//console.log(xhr.responseText);
}
};
xhr.send(params);
} function formatDebugInfo(id){
var debuginfo = "<p><strong>"
+ loggerPool[id].description + "</strong><br/>";
if(loggerPool[id].avgRunTime){
debuginfo += "average run time: " + loggerPool[id]
.avgRunTime + "ms<br/>";
}else{
debuginfo += "run time: " + loggerPool[id].runtime
+ "ms<br/>";
}
debuginfo += "path: " + loggerPool[id].url
+ "<br/>";
debuginfo += "useragent: " + loggerPool[id].useragent
+ "<br/>"; debuginfo += "Perceived Time: " +
loggerPool[id].perceivedTime + "<br/>";
debuginfo += "Redirect Time: " +
loggerPool[id].redirectTime + "<br/>";
debuginfo += "Cache Time: " +
loggerPool[id].cacheTime + "<br/>";
debuginfo += "DNS Lookup Time: " +
loggerPool[id].dnsLookupTime + "<br/>";
debuginfo += "tcp Connection Time: " +
loggerPool[id].tcpConnectionTime + "<br/>";
debuginfo += "roundTripTime: "+
loggerPool[id].roundTripTime + "<br/>";
debuginfo += "pageRenderTime: " +
loggerPool[id].pageRenderTime + "<br/>";
debuginfo += "</p>";
return debuginfo
} return {
startTimeLogging: function(id, descr,drawToPage
,logToServer){
loggerPool[id] = new TestResults();
loggerPool[id].id = id;
loggerPool[id].startTime = performance.now();
loggerPool[id].description = descr;
loggerPool[id].drawtopage = drawToPage;
loggerPool[id].logtoserver = logToServer
}, stopTimeLogging: function(id){
loggerPool[id].stopTime = performance.now();
calculateResults(id);
setResultsMetaData(id);
if(loggerPool[id].drawtopage){
drawToDebugScreen(id);
}
if(loggerPool[id].logtoserver){
logToServer(id);
}
}, logBenchmark: function(id, timestoIterate, func, debug, log){
var timeSum = 0;
for(var x = 0; x < timestoIterate; x++){
perfLogger.startTimeLogging(id, "benchmarking "+ func,
false, false);
func();
perfLogger.stopTimeLogging(id)
timeSum += loggerPool[id].runtime
}
loggerPool[id].avgRunTime = timeSum/timestoIterate
if(debug){
drawToDebugScreen(id)
}
if(log){
logToServer(id)
}
}, //expose derived performance data
perceivedTime: function(){
return _pTime;
},
redirectTime: function(){
_redirTime;
},
cacheTime: function(){
return _cacheTime;
},
dnsLookupTime: function(){
return _dnsTime;
},
tcpConnectionTime: function(){
return _tcpTime;
},
roundTripTime: function(){
return _roundtripTime;
},
pageRenderTime: function(){
return _renderTime;
}, showPerformanceMetrics: function(){
this.startTimeLogging("no_id", "draw perf data to page"
,true,true);
this.stopTimeLogging("no_id"); } }
}(); performance.now = (function() {
return performance.now ||
performance.mozNow ||
performance.msNow ||
performance.oNow ||
performance.webkitNow ||
function() { return new Date().getTime(); };
})();
实现和可视化
要想使用 perfLogger.js 脚本可视化浏览器内的性能,可以将该脚本嵌入页面中,在页面的 onload
事件上,您可以将性能数据推送回端点,将它们保存为一个平面文件。GitHub 中的 perfLogger
项目附带了一个 PHP 脚本,名为 savePerfData.php,该脚本恰好提供了此功能。该文件的源代码如清单 6 所示。
清单 6. savePerfData.php 的源代码
<?php
require("util/fileio.php"); $logfile = "log/runtimeperf_results.txt";
$benchmarkResults = formatResults($_POST["data"]); saveLog($benchmarkResults, $logfile); function formatResults($r){
print_r($r);
$r = stripcslashes($r);
$r = json_decode($r);
if(json_last_error() > 0){
die("invalid json");
}
return($r);
} function formatNewLog($file){
$headerline = "IP, TestID, StartTime, StopTime, RunTime,
URL, UserAgent, PerceivedLoadTime, PageRenderTime, RoundTripTime,
TCPConnectionTime, DNSLookupTime, CacheTime, RedirectTime";
appendToFile($headerline, $file);
} function saveLog($obj, $file){
if(!file_exists($file)){
formatNewLog($file);
}
$obj->useragent = cleanCommas($obj->useragent);
$newLine = $_SERVER["REMOTE_ADDR"] . "," . $obj->id .","
. $obj->startTime . "," . $obj->stopTime . "," . $obj->runtime . ","
. $obj->url . "," . $obj->useragent . $obj->perceivedTime . ","
. $obj->pageRenderTime . "," . $obj->roundTripTime . ","
. $obj->tcpConnectionTime . "," . $obj->dnsLookupTime . ","
. $obj->cacheTime . "," . $obj->redirectTime;
appendToFile($newLine, $file);
} function cleanCommas($data){
return implode("", explode(",", $data));
} ?>
这个 PHP 实际上将 perfLogger.js 发送的 POST 数据保存为一个平面文件,格式如清单 7 所示。
清单 7. perfLogger.js 发送的 POST 数据
IP, TestID, StartTime, StopTime, RunTime, URL, UserAgent,
PerceivedLoadTime, PageRenderTime, RoundTripTime, TCPConnectionTime,
DNSLookupTime, CacheTime, RedirectTime
75.149.106.130,page_render,1341243219599,1341243220218,619
,http://www.tom-barker.com/blog/?p=x,Mozilla/5.0 (Macintosh;
Intel Mac OS X 10.5; rv:13.0) Gecko/20100101
Firefox/13.0.1790,261,-2,36,0,-4,0
此时此刻,您可以看到有一些很好的数据点值得关注,例如:
- 用户代理所用的平均加载时间
- 在平均加载时间方面,HTTP 事务流程的哪一部分所用的时间最多
- 总体的加载时间分布
在 GitHub 存储库中,还有一个 R 脚本,名为 runtimePerformance.R,该脚本将会摄取您生成的这个日志文件,并实现数据可视化(参见清单 8)。
清单 8. 名为 runtimePerformance.R 的 R 脚本
dataDirectory <- "/Applications/MAMP/htdocs/lab/log/"
chartDirectory <- "/Applications/MAMP/htdocs/lab/charts/"
testname = "page_render" perflogs <- read.table(paste(dataDirectory, "runtimeperf
_results.csv", sep=""), header=TRUE, sep=",")
perfchart <- paste(chartDirectory, "runtime_",testname, ".
pdf", sep="") loadTimeDistrchart <- paste(chartDirectory,
"loadtime_distribution.pdf", sep="")
requestBreakdown <- paste(chartDirectory,
"avgtime_inrequest.pdf", sep="")
loadtime_bybrowser <- paste(chartDirectory,
"loadtime_bybrowser.pdf", sep="") pagerender <- perflogs[perflogs$TestID == "page_render",]
df <- data.frame(pagerender$UserAgent, pagerender$RunTime)
df <- by(df$pagerender.RunTime, df$pagerender.UserAgent, mean)
df <- df[order(df)] pdf(perfchart, width=10, height=10)
opar <- par(no.readonly=TRUE)
par(las=1, mar=c(10,10,10,10))
barplot(df, horiz=TRUE)
par(opar)
dev.off() getDFByBrowser<-function(data, browsername){
return(data[grep(browsername, data$UserAgent),])
} printLoadTimebyBrowser <- function(){
chrome <- getDFByBrowser(perflogs, "Chrome")
firefox <- getDFByBrowser(perflogs, "Firefox")
ie <- getDFByBrowser(perflogs, "MSIE") meanTimes <- data.frame(mean(chrome$PerceivedLoadTime),
mean(firefox$PerceivedLoadTime), mean(ie$PerceivedLoadTime))
colnames(meanTimes) <- c("Chrome", "Firefox",
"Internet Explorer")
pdf(loadtime_bybrowser, width=10, height=10)
barplot(as.matrix(meanTimes), main="Average Perceived Load
Time\nBy Browser", ylim=c(0, 600), ylab="milliseconds")
dev.off()
} pdf(loadTimeDistrchart, width=10, height=10)
hist(perflogs$PerceivedLoadTime, main="Distribution of
Perceived
Load Time", xlab="Perceived Load Time in Milliseconds",
col=c("#CCCCCC"))
dev.off() avgTimeBreakdownInRequest <- function(){ #expand exponential notation
options(scipen=100, digits=3) #set any negative values to 0
perflogs$PageRenderTime[perflogs$PageRenderTime < 0] <- 0
perflogs$RoundTripTime[perflogs$RoundTripTime < 0] <- 0
perflogs$TCPConnectionTime[perflogs$TCPConnectionTime < 0] <- 0
perflogs$DNSLookupTime[perflogs$DNSLookupTime < 0] <- 0 #capture avg times
avgTimes <- data.frame(mean(perflogs$PageRenderTime),
mean(perflogs$RoundTripTime), mean(perflogs$TCPConnectionTime),
mean(perflogs$DNSLookupTime))
colnames(avgTimes) <- c("PageRenderTime", "RoundTripTime",
"TCPConnectionTime", "DNSLookupTime")
pdf(requestBreakdown, width=10, height=10)
opar <- par(no.readonly=TRUE)
par(las=1, mar=c(10,10,10,10))
barplot(as.matrix(avgTimes), horiz=TRUE, main="Average Time
Spent\nDuring HTTP Request", xlab="Milliseconds")
par(opar)
dev.off() } printLoadTimebyBrowser()
avgTimeBreakdownInRequest()
这个 R 脚本附带了一些内置的功能,例如 printLoadTimebyBrowser
和 avgTimeBreakdownInRequest
。图 4 是 printLoadTimebyBrowser
输出的屏幕截图。
图 4. printLoadTimebyBrowser
的输出
图 5 是 avgTimeBreakdownInRequest
的屏幕截图。
图 5. avgTimeBreakdownInRequest
代码的输出code
在将性能数据加载到 R 会话中之后,所有已摄取的数据指标都存储在一个名为 perflogs
的数据帧内,这样您就可以访问单独的列,如清单 9 所示。
清单 9. 已摄取的指标存储在名为 perflogs 的数据帧内
perflogs$PerceivedLoadTime
perflogs$ PageRenderTime
perflogs$RoundTripTime
perflogs$TCPConnectionTime
perflogs$DNSLookupTime
perflogs$UserAgent
该代码支持您开始执行一些探索性的数据分析,比如创建柱状图来查看用户群的感知加载时间的分布,如清单 10 所示。
清单 10. 用户群的感知加载时间
hist(perflogs$PerceivedLoadTime, main="Distribution of
Perceived Load Time", xlab="Perceived Load Time in Milliseconds",
col=c("#CCCCCC"))
dev.off()
图 6 显示了用户群的感知加载时间分布柱状图。
图 6. 用户群的感知加载时间分布柱状图
结束语
本文帮助您更好地了解了 Performance
对象中一些功能,并模拟了如何使用可从该对象收集的浏览器内指标。通过这里介绍的模型,您可以从实际用户群中捕获真正的用户指标,这是您可以收集并跟踪的最有价值的性能指标类型。
如果愿意的话,您还可以使用该模型中的 perfLogger.js 和所有实用程序文件。您可以随时发表您自己的意见以及对该项目的更改。
使用 W3C Performance 对象通过 R 和 JavaScript 将浏览器内的性能数据可视化[转]的更多相关文章
- JavaScript使用浏览器内置XML解析器解析DOM对象
所有现代浏览器都内建了供读取和操作 XML 的 XML 解析器.解析器把 XML 转换为 XML DOM 对象 (可通过 JavaScript 操作的对象). 一.获取DOM对象 XMLHttpReq ...
- JavaScript使用浏览器内置XMLHttpRequest对象执行Ajax请求
所有现代浏览器均支持 XMLHttpRequest 对象(IE5 和 IE6 使用 ActiveXObject).XMLHttpRequest 用于在后台与服务器交换数据.这意味着可以在不重新加载整个 ...
- 4款开源免费的数据可视化JavaScript库
概述:交互式数据可视化在很大程度上取决于JavaScript库的任务能力.在这篇文章中,我们将看看四个JavaScript库:D3,InfoVis,Processing.js,和Recline.js. ...
- web计时机制——performance对象
前面的话 页面性能一直都是Web开发人员最关注的领域.但在实际应用中,度量页面性能的指标,是提高代码复杂程度和巧妙地使用javascript的Date对象.Web Timing API改变了这个局面, ...
- [转]web计时机制——performance对象
页面性能一直都是Web开发人员比较关注的领域.但在实际应用中,度量页面性能的指标,是javascript的Date对象.Web Timing API改变了这个局面,让开发人员通过javascript就 ...
- JavaScript学习07 内置对象
JavaScript内置对象 图像对象 导航对象 窗口对象 屏幕对象 事件对象 历史对象 文件对象(重要) 锚点对象 链接对象 框架对象 表单对象(重要) 位置对象 JS Window 窗口对象:ht ...
- javascript中的内置对象
2015.12.1 javascript中的内置对象 复习: 1.js中的内置函数 alert prompt write parseInt parseFloat eval isNaN document ...
- JavaScript 3种内置对象
前面我们学了对象,如何创建对象及使用对象. 内置对象不需要实例化,就可以使用. 可以通俗地理解,在内存里的东东是对象,也就是实例化好的.在磁盘里的东东是类,需要实例化才能使用.实例化后的东东在内存里. ...
- javaScript中Math内置对象基本方法入门
概念 Math 是javaScript的内置对象,包含了部分数学常数属性和数学函数方法. Math 不是一个函数对象,用户Number类型进行使用,不支持BigInt. Math 的所有属性与方法都是 ...
随机推荐
- Murano Weekly Meeting 2016.05.31
Meeting time: 2016.May.31 1:00~2:00 Chairperson: Kirill Zaitsev, from Mirantis Meeting summary: 1.A ...
- IAR6.1的工程迁移到IAR6.5不能用的解决方法
1.重命名过时的CMSIS头文件 "... \ CMSIS \ CM3 \ CoreSupport \ core_cm3.h 比如:core_cm3.h.old 2.启用CMSIS:项目- ...
- pat1017. Queueing at Bank (25)
1017. Queueing at Bank (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Supp ...
- OAuth2.0和企业内部统一登录,token验证方式,OAuth2.0的 Authorization code grant 和 Implicit grant区别
统一登录是个很多应用系统都要考虑的问题,多个项目的话最好前期进行统一设计,否则后面改造兼容很麻烦: cas认证的方式:新公司都是老项目,用的是cas认证的方式,比较重而且依赖较多,winform的项目 ...
- 把js生成的内容放入网页原有的div上
<script> ; ; //5列 ); ; var htmlstr="<table style='position:absolute;top:9%;left:10%; b ...
- laravel的nginx配置
最近阅读laravel官方文档 发现了关于nginx的推荐配置 Nginx 如果你使用 Nginx ,在你的网站配置中加入下述代码将会转发所有的请求到 index.php 前端控制器. locatio ...
- canvas制作运动的小球
<!DOCTYPE html> <head> <title>canvas</title> <style> .canvas{ border: ...
- python网络编程-paramiko模块
paramiko模块 该模块基于SSH用于连接远程服务器并执行相关操作 参考文档 SSHClient 用于连接远程服务器并执行命令 import paramiko #创建SSH对象 ssh = par ...
- anaconda和jupyter notebook使用方法
查看安装的conda版本 conda --version 如果没有安装anaconda,可以从以下链接下载anaconda或者miniconda,两者安装一个就可以了 miniconda大约50M h ...
- Arduino入门教程--课前准备--Arduino驱动安装及1.0 IDE菜单介绍
编译器版本:Arduino 1.0实验器件:ocrobot mango控制板(Arduino兼容)一块 Arduino控制板到手后,首先需要在电脑上把驱动装上,这样才可以进行各种实验. 第一步需要把A ...