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>



  • 相关阅读:
    win10 UWP button
    内网分享资源
    内网分享资源
    CF724F Uniformly Branched Trees
    win10 UWP FlipView
    win10 UWP FlipView
    win10 UWP FlipView
    搭建阿里云 centos mysql tomcat jdk
    搭建阿里云 centos mysql tomcat jdk
    win10 UWP 申请微软开发者
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5136773.html
Copyright © 2011-2022 走看看