zoukankan      html  css  js  c++  java
  • WebKit的历史项管理

    标准定义

    关于历史的管理,和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>



  • 相关阅读:
    leetcode每日刷题计划-简单篇day10
    leetcode每日刷题计划-简单篇day9
    leetcode每日刷题计划-简单篇day8
    leetcode每日刷题计划-简单篇day7
    leetcode每日刷题计划-简单篇day6
    leetcode每日刷题计划-简单篇day5
    leetcode每日刷题计划-简单篇day4
    leetcode每日刷题计划-简单篇day3
    设计模式解决 if-else
    线程池
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5136773.html
Copyright © 2011-2022 走看看