您的位置:首页 > 其它

WebKit的历史项管理

2016-01-17 09:15 363 查看

标准定义

关于历史的管理,和HTML页面载入一样,都有其相应的标准。地址例如以下:
WhatWG: https://html.spec.whatwg.org/multipage/browsers.html#history

当中关于历史项的要点例如以下:

1. 在onload之前。非用户操作引起的导航操作不建立历史项。

非用户操作比方页面中指定的Timer改动location或iframe的src引发的导航操作。而用户点击发起的Timer,则在timer中记录下在发起timer时标记手势来源。但有一个例外是由还有一个Timer发起的Timer或是反复运行的Timer, 则仅针对第一次运行有效(以nesting level标识)。

2. 子Frame载入完毕仍有未载入的上层Frame, 则不创建历史项。

3. 当前Frame仅仅有一个历史项。且为about:blank, 则不创建历史项。

4. 假设页面跳转的间隔小于1s,则不创建历史项。


关于Timer的nesting level能够參考这里:
http://www.w3.org/html/wg/drafts/html/CR/webappapis.html#timer-nesting-level

以上规则相应于以下三个WebKit的函数:

a. LockBackForwardList NavigationScheduler::mustLockBackForwardList(Frame& targetFrame)
LockBackForwardList NavigationScheduler::mustLockBackForwardList(Frame& targetFrame)
{
// Non-user navigation before the page has finished firing onload should not create a new back/forward item.
// See https://webkit.org/b/42861 for the original motivation for this.
if (!ScriptController::processingUserGesture() && targetFrame.loader().documentLoader() && !targetFrame.loader().documentLoader()->wasOnloadHandled())
return LockBackForwardList::Yes;

// Navigation of a subframe during loading of an ancestor frame does not create a new back/forward item.
// The definition of "during load" is any time before all handlers for the load event have been run.
// See https://bugs.webkit.org/show_bug.cgi?id=14957 for the original motivation for this.
for (Frame* ancestor = targetFrame.tree().parent(); ancestor; ancestor = ancestor->tree().parent()) {
Document* document = ancestor->document();
if (!ancestor->loader().isComplete() || (document && document->processingLoadEvent()))
return LockBackForwardList::Yes;
}
return LockBackForwardList::No;
}

b. HistoryController::currentItemShouldBeReplaced() const
{
// From the HTML5 spec for location.assign():
// "If the browsing context's session history contains only one Document,
// and that was the about:blank Document created when the browsing context
// was created, then the navigation must be done with replacement enabled."
return m_currentItem && !m_previousItem && equalIgnoringCase(m_currentItem->urlString(), blankURL());
}

c. void NavigationScheduler::scheduleRedirect(double delay, const URL& url)
{
if (!shouldScheduleNavigation(url))
return;
if (delay < 0 || delay > INT_MAX / 1000)
return;
if (url.isEmpty())
return;
// We want a new back/forward list item if the refresh timeout is > 1 second.
if (!m_redirect || delay <= m_redirect->delay()) {
LockBackForwardList lockBackForwardList = delay <= 1 ? LockBackForwardList::Yes : LockBackForwardList::No;
schedule(std::make_unique<ScheduledRedirect>(delay, m_frame.document()->securityOrigin(), url, LockHistory::Yes, lockBackForwardList));
}
}

页面问题分析

1. Timer问题

Timer最大的问题来源于Timer Nesting Level的认定。

最初WebKit建一个全局的变量记录, easy受到不同页面。frame中Timer的影响。
比方用户点击一条链接就使用一个Timer跳转,假设这个Timer创建时。恰好有还有一个repeat timer还在循环运行, 且未载入完毕(onload事件没有运行), 那它就无法创建历史项,由于这时全局的nesting level大于1,将不会记录为手势触发的跳转。WebKit提交的(https://bugs.webkit.org/show_bug.cgi?id=136401 [^]), 本意用于避免多线程訪问的问题,也刚好攻克了嵌套层次错误的问题。
如今仍然有一种情况下,这个问题还会存在。见 https://bugs.webkit.org/show_bug.cgi?
id=137631。

如以下測试页面所看到的。当在一个document中。有一个repeat timer运行后, 且未载入完毕(onload事件没有运行)。其他Timer的跳转仍然无法创建历史项。<html>
<head>
</head>
<body>
<input type="button" value="Goto next page" onclick="gotoNextPage();">
<input type="button" value="Start repeating timer" onclick="startRepeatingTimer();">
<p>
<div id="Timer">Paused</div>
</p>
<script type="text/javascript">

function gotoNextPage(){
setTimeout(function(){location.href="http://www.webkit.org/";},300);
}

function startRepeatingTimer(){
setInterval(function(){document.getElementById("Timer").innerHTML="Running...";},500);
}
</script>

<img src="http://therecoveringpolitician.com/wp-content/uploads/2013/01/moderate.jpg" width="640" height="480">
<img src="http://cullogo.com/full/wallpapers-high-resolution-widescreen-hd-pk.jpg" width="640" height="480">
<img src="http://www.highresolutionwallpapers.net/wallpapers/autumn-1680x1050.jpg" width="640" height="480">
</body>
</html>

2. 载入规则导致多余历史项问题

有点页面(华声论坛)由于页面在iframe的初始化及动态改变时,看起来两个src是同样的,都带有ampersand, 一个由HTML指定,还有一个由JavaScript设定。

问题在于JavaScript不会转换ampersand, 这样就相当于iframe载入了两个不同的页面。从而产生了两个历史项。
使用以下的測试页面能够重现这个问题, 注意页面中两处http://m.baidu.com的写法:<html>
<head>
</head>
<body>
<p>
<div id="info">Loading...</div>
</p>
<script type="text/javascript">
setTimeout(function(){ attr("sub_iframe","http://m.baidu.com/?abc=23&t=20080225");},5000);

function attr(id,url){
var obj=document.getElementById(id);
obj.setAttribute("src", url);
}

window.onload=function(){
document.getElementById("info").innerHTML="Loaded.";
}

</script>
<iframe src="http://m.baidu.com/?abc=23&t=20080225" id="sub_iframe" width="320" height="480"></iframe><br/>
</body>
</html>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: