UIWebView第一次请求太慢

16

我正在使用UIWebView在我的应用程序中呈现网页内容。 我观察到当应用程序启动时,即loadRequest时的初始请求需要很长时间来呈现内容。 但是,我没有跟踪的后续请求要快得多。


为了确认这一点,我创建了一个独立的应用程序,只有一个UIWebView。 这是我添加的单行代码:

[wkBrowser loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.yahoo.com"]]];

结果相同。加载页面大约需要 15-20 秒时间。但是在点击网页上的任何链接时,加载下一页需要 3-5 秒的时间。我确实使用了UIWebView委托函数didFailLoadWithError,但从未出现错误。
问题

  1. 为什么第一次网页请求如此缓慢?
  2. 除了缓存之外,我怎样才能使它更快?

你是在模拟器或者其他设备上工作吗? 可能是你的设备开启了某些代理。 - aBilal17
@aBilal17:我正在设备上进行测试。不只是一个,我在三个不同的设备上测试了这个。 - Nitish
请添加以下这行代码并检查: web.scrollView.delaysContentTouches = NO; - aBilal17
@aBilal17:没有任何区别。 - Nitish
它只发生在https://www.yahoo.com吗?其他网站呢? - lambao
显示剩余6条评论
6个回答

5
主要原因是,当您第一次调用URL请求时,接收端的服务器会根据所请求的设备浏览器(如移动设备、桌面设备)尝试显示信息。这就是您看到有些延迟的地方。
  • 服务器需要一些时间来解析请求源浏览器类型并根据浏览器类型作出响应。此值从浏览器内部发送。在移动Safari和桌面Safari之间存在差异。
  • 服务器在接收到请求后,以兼容设备类型的页面响应您,(大多数域服务器都在内部实现此功能,即响应式页面)。
  • 如果您想要“无延迟”的情况,请尝试调用相关门户的精确移动版本。
  • 随后的请求将从已知的类型浏览器中处理,从而减少响应延迟。
希望这能解决疑问。

当大多数网站使用响应式设计方法,使界面自动适应屏幕大小时,这是否重要呢?因此,移动设备不需要调用“其他”版本的门户网站吗? - Bourne
4
我不同意。我有一个静态页面从应用程序包中显示:let bundlePath = Bundle.main.bundlePath.stringByAppendingPathComponent("description.html")let url = URL(fileURLWithPath: bundlePath)let request = URLRequest(url: requestURL)webView.loadRequest(request)那么网络和服务器延迟在哪里呢? - One In a Million Apps

3
第一次加载比后续加载慢的原因有多种。
首先,你的应用程序链接到动态框架。动态链接分辨率是惰性执行的。因此,每当您第一次使用UIWebView时,都会涉及解析您从动态库中使用的符号的非常小的开销。 UIWebView本身可能依赖于需要进行动态链接的一些更多内部库,从而增加了这种开销。
然后还有UIWebView本身的实现。 UIWebView的内部很可能涉及初始化惰性的数据结构。
然后还有内存分配方面。每当您进行第一次页面加载时,您的应用程序的内存使用量会比第二次页面加载时增加得多。为处理页面加载分配足够的内存会增加开销,但是一旦完成,iOS将在一段时间内将该内存委托给您的应用程序,超过了在内存释放以使您的应用程序在其内存使用量达到峰值时更快。
有人建议在两个页面之间可能存在缓存资源。即使两个页面都不同且首次加载,它们也可能共享一个通用的css文件或一个通用的javascript文件,例如jQuery。然后浏览器能够重复使用这些缓存资源。
总的来说,有很多这样的因素可以解释为什么第一次页面加载可能比后续页面加载慢。您可以通过在两个页面加载期间对应用程序进行分析来了解UIWebView实际上正在执行的操作。

3
您的第一个问题的答案如下:
当您首次加载请求时,Webview会下载并缓存所有文件,例如CSS、图像等。之后,当您单击指向同一网站的另一页的URL时,它基本上会从缓存中加载页面,而不是再次进行下载,这样可以节省大量时间。

但是当应用程序首次启动时,第二个页面也会被加载。那个页面在那时没有缓存。只有当再次访问页面时,页面才会从缓存中加载。 - Nitish

1
你的第一个问题的答案: 当您首次加载请求时,Webview会下载并缓存所有文件,例如css、图片等。之后,当您点击指向同一网站的另一页的url时,它基本上从缓存中加载而不是再次下载,并且节省了大量时间。

0

在您的应用程序启动期间,只需将UIWebView加载到屏幕外的虚拟页面即可。这在真实设备上运行良好。 在AppDelegates的didFinishLaunchingWithOptions方法中实现。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        self.loadInitialWebView()
        return true
    }

func loadInitialWebView() {
        var dummyWebView : UIWebView? = UIWebView(frame: UIScreen.main.bounds)
        let htmlString = "<!doctype html><html lang=en><head><meta charset=utf-8><title>dummy</title></head><body><p>dummy content</p></body></html>"
        dummyWebView?.loadHTMLString(htmlString, baseURL: nil)
        dummyWebView = nil;
    }

0

在这里你可以做的一件事情是实现一个类似于以下链接的NSURLProtocol,以查看正在发生的情况:http://www.raywenderlich.com/59982/nsurlprotocol-tutorial

并在canInitWithRequest方法中拦截您的请求。

这将至少向您展示您的请求正在发生什么。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接