标准定义

关于历史的管理,和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&amp;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&amp;t=20080225" id="sub_iframe" width="320" height="480"></iframe><br/>
  </body>
</html>

WebKit的历史项管理的更多相关文章

  1. WebKit历史项管理的实现

    历史项管理依据标准定义,由Page管理一个Joint Session History, 包括了各个子Frame的历史项.逻辑上相应例如以下的关系: 从上面看三个层次:Page,Frame,以及JS B ...

  2. ASP.NET Core 1.0 中的依赖项管理

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  3. RDIFramework.NET ━ 9.7 操作权限项管理 ━ Web部分

    RDIFramework.NET ━ .NET快速信息化系统开发框架 9.7 操作权限项管理 -Web部分 随着经济全球化趋势的发展和企业间竞争的加剧,企业对管理要求不断变化.提高,越来越多的信息都表 ...

  4. History API与浏览器历史堆栈管理

    移动端开发在某些场景中有着特殊需求,如为了提高用户体验和加快响应速度,常常在部分工程采用SPA架构.传统的单页应用基于url的hash值进行路由,这种实现不存在兼容性问题,但是缺点也有--针对不支持o ...

  5. windows启动项管理

    在运行框中输入 msconfig 选择启动栏 会跳转到任务管理器,可以管理启动项,可以看到我的启动项里有nc病毒 ,点击禁用即可.

  6. 什么是Maven? 使用Apache Maven构建和依赖项管理

    通过优锐课java架构学习中,学到了不少干货,整理分享给大家学习. 开始使用最流行的Java构建和依赖管理工具Maven Apache Maven是Java开发的基石,也是Java使用最广泛的构建管理 ...

  7. Linux命令:history命令历史的管理及用法

    bash可以保存的过去曾经执行过的命令.当某个用户登录到shell中,会读取该用户家目录中的~/.bash_history文件,并将历史命令列表保存到内存中.当用户退出当前shell时,会将内存中的历 ...

  8. Linux历史命令管理以及用法

    history [-c] [-d offset] [n] history -anrw [filename] history -ps arg [arg...] -c: 清空命令历史 -d offset: ...

  9. ubuntu mint 开机启动项管理

    使用工具 sysv-rc-conf,需要安装. 点击打开链接http://blog.chinaunix.net/uid-21516619-id-1825027.html

随机推荐

  1. 回归 WordPress

    一直很喜欢用WordPress,使用方便,模板容易定制,国内建站可选择的虚拟主机多.自从WordPress升级后,官方网站打不开,从 GitHub 安装 WordPress 后无法浏览在线的主题.一切 ...

  2. extend vg(pv,lv)use HotPlug Storage PV for VMI(ECC Env)

    Preface: 前期存储未规划好,业务快速扩展,数据高安全需求(异地,More one copy),需求多多?NM干着干着活就会时不时的坑爹起来了!particularly Real Product ...

  3. powerdesigner for sqlserver的一些实用配置

    在实用powerdesigner生成sqlserver 数据表时常常遇到一些问题: 1.数据中定义的字段名称相同生成物理模型时会报错. 2.数据各表之间的主键不能定义一样的名称. 我现在的需求是将数据 ...

  4. 安装python模块

    要想在python中使用import的一些模块,前提是要安装这些模块. 可以使用pip来导入模块. 打开终端,输入命令: sudo easy_install pip 安装好pip后,就可以使用pip来 ...

  5. CRM需要注意的一些事,修改字段类型

    crm字段类型如果变了,比如文本类型变为查找类型,要新建命名跟原来不一样,千万不能删除以前的字段再建原来的一样的,那样如果导到正式系统会造成无法导入,执行sql失败, 切记切记.可以字段名后加2,或者 ...

  6. 2014.9.16HTML表单CSS

    (一)表格 合并单元格(少用) (合并列) 1.先选中要合并的2个或多个单元格,然后点击以下图标 代码:<td colspan="2"> </td> 2.设 ...

  7. ubuntu10.04 安装NVIDIA GT 420M驱动

    安装ubuntu已经好几天了,由于显卡驱动没装,屏幕在600X800下的效果很难看,于是就想办法,查阅资料终于安装成功了,下面将我的安装方法记录下来以供大家参考. 借鉴:ubuntu12.04下安装N ...

  8. 经典SQL语句集锦

      下列语句部分是MsSql语句,不可以在access中使用. SQL分类: DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE) DML—数据操纵语言(SELECT,DELET ...

  9. VS2013无法链接到TFS (转)

    VS2013无法链接到TFS(Visual studio online),错误TF31001,TF31002   TF31002: Unable to connect to VisualStudio ...

  10. (转)Java通过axis调用WebService

    转自:http://blog.csdn.net/wanglha/article/details/49679825 转载地址:http://www.linuxidc.com/Linux/2015-06/ ...