首页 > 其他分享 >深入解析 WKWebView 的 didFinish 回调时机:页面加载与异步操作的处理

深入解析 WKWebView 的 didFinish 回调时机:页面加载与异步操作的处理

时间:2024-11-07 16:23:52浏览次数:1  
标签:异步 触发 iOS didFinish 加载 WKWebView 页面

在 iOS 开发中,我们经常会用 WKWebView 来加载和展示 H5 页面。通常,开发者会在 WKWebViewdidFinish 方法中处理页面加载完成后的逻辑,例如更新 UI 或执行后续操作。然而,didFinish 的触发时机并不总是如我们所期待,它并不会等待所有异步操作(如 AJAX 请求、图片加载等)完成后再执行。

本文将深入探讨 didFinish 的触发时机及其受哪些加载内容的影响,同时提供一种方法,确保页面在所有异步操作完成后再触发回调通知 iOS。


WKWebView 的 didFinish 回调触发时机

在 iOS 的 WKWebView 中,didFinish 回调的触发代表了页面 HTML 文档的初步加载完成。这意味着浏览器已经解析并加载了页面的主要内容结构,但并未考虑页面中的所有资源(如图片、CSS、JavaScript、AJAX 请求等)是否加载完毕。因此,理解 didFinish 的触发时机及其受哪些加载内容影响,对合理设计页面加载完成的处理逻辑至关重要。

以下是 didFinish 回调受影响的几种内容:

  1. HTML 文档的解析和加载

    didFinish 回调会在 HTML 文档加载完成后触发。也就是说,当 WKWebView 获取到并渲染了页面的初始 HTML 结构后,didFinish 就会被触发。这一过程不包括后续的资源加载,因此只代表页面的基础结构已加载完成,而非页面的所有内容。

  2. CSS 和 JavaScript 文件的加载

    外部 CSS 和 JavaScript 文件的加载也会影响 didFinish 的触发,特别是外部 CSS 的加载。浏览器在初步渲染页面时需要完整的样式信息,因此通常会等待 CSS 文件的加载完成再触发 didFinish

    同样地,对于页面中同步加载的 JavaScript(没有 asyncdefer 标记的脚本),浏览器会在加载并执行完脚本后才触发 didFinish。然而,异步加载的 JavaScript 则不影响该回调,它们的执行可能在 didFinish 触发后继续进行。

  3. 图片和其他媒体资源的加载

    页面中的图片、视频和音频等媒体资源的加载时间不影响 didFinish 的触发。即使图片还未完全加载,didFinish 依然会在 HTML 和 CSS 加载完成后触发。因此,如果页面中有大量的图片或其他媒体文件,didFinish 回调会提前触发,而图片加载可能仍在进行。

  4. AJAX 请求和动态内容加载

    许多现代 H5 页面会在加载后发起 AJAX 请求以获取动态数据。didFinish 回调不会等待 AJAX 请求完成,即使这些请求的数据对页面显示至关重要。也就是说,页面在视觉上可能看似完成加载,但实际数据尚未加载完毕。因此,若希望在 AJAX 请求完成后再触发回调,必须通过额外的手段进行控制。

  5. <iframe> 和嵌套资源的加载

    如果页面中包含 <iframe> 元素,didFinish 会在该 iframe 的内容加载完成后触发。嵌套的 iframe 也是如此,didFinish 只会在最外层框架的内容加载完成时触发。然而,嵌套框架中的进一步异步加载操作,如同 AJAX 请求和媒体加载一样,也不会影响 didFinish 的触发。


如何确保页面所有异步操作完成后再触发 iOS 回调

由于 didFinish 回调的触发不依赖于页面的所有资源加载和异步操作完成,若我们希望在页面的所有异步请求和资源加载完毕后再通知 iOS 端,可以通过以下方法实现:

  1. 在 H5 页面中实现异步操作的完成检测
    可以在页面中使用 JavaScript 控制异步操作的完成。例如,使用 Promise.all 等手段确保页面中的所有 AJAX 请求完成后触发一个事件,表示页面所有内容已经加载完毕。

  2. 使用 JavaScript 向 iOS 端发送消息
    在 H5 页面所有异步操作完成后,通过 window.webkit.messageHandlers 向 iOS 发送消息,以便触发 iOS 的相应回调,从而达到“所有资源加载完成后再通知 iOS”的效果。

代码示例

以下是一个完整的实现示例:

1. H5 页面代码(JavaScript)

在页面中使用 Promise.all 来监听所有异步操作完成后再通知 iOS:

function onAllAsyncOperationsComplete() {
    if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.notifyCompletion) {
        window.webkit.messageHandlers.notifyCompletion.postMessage("all_done");
    }
}

// 假设页面有多个 AJAX 请求
Promise.all([
    fetch('https://example.com/api/data1'),
    fetch('https://example.com/api/data2'),
    // 其他异步操作
]).then(responses => {
    // 确保所有异步操作完成后调用 onAllAsyncOperationsComplete
    onAllAsyncOperationsComplete();
}).catch(error => {
    console.error("异步操作失败:", error);
});
2. iOS 端代码(Swift)

在 iOS 端,通过注册 JavaScript 消息处理来接收通知,并在接收到通知后执行后续操作:

import WebKit

class ViewController: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {
    
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let contentController = WKUserContentController()
        contentController.add(self, name: "notifyCompletion")  // 注册 JavaScript 通知
        
        let config = WKWebViewConfiguration()
        config.userContentController = contentController
        
        webView = WKWebView(frame: self.view.bounds, configuration: config)
        webView.navigationDelegate = self
        self.view.addSubview(webView)
        
        if let url = URL(string: "https://yourwebsite.com") {
            let request = URLRequest(url: url)
            webView.load(request)
        }
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // 在页面加载完成后执行其他逻辑
        print("页面加载完成")
    }
    
    // 处理 JavaScript 中发送的通知
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "notifyCompletion" {
            if let body = message.body as? String, body == "all_done" {
                print("所有异步操作已完成,触发回调")
                // 执行你希望在所有异步操作完成后执行的代码
            }
        }
    }
}

总结

WKWebViewdidFinish 回调在 HTML 文档结构加载完成后触发,但不会等待页面中的所有异步操作和资源加载完成。因此,为了确保在页面全部资源加载完毕后再通知 iOS,可以通过 H5 页面中的 JavaScript 控制异步加载的完成状态,并使用 window.webkit.messageHandlers 与 iOS 端通信,从而实现更准确的加载完成时机控制。

标签:异步,触发,iOS,didFinish,加载,WKWebView,页面
From: https://www.cnblogs.com/PaulpauL/p/18532596

相关文章

  • es6,for....of是异步的嘛? 如何实现循环中异步实现
    for...of循环本身不是异步的,它是同步执行的。这意味着for...of循环会按顺序依次执行每一项,直到循环结束。如果循环中的操作是异步的(例如,async函数或者Promise),则这些异步操作会并发执行,但for...of本身不会等待这些操作完成,除非你显式地处理它们。让我们通过一个例子来说明......
  • 微信小程序使用Promise异步请求
     在微信小程序中,如果你希望在一个HTTP请求完成后再继续执行下面的代码,可以将后续代码放入请求的回调函数中。如果不想使用嵌套的回调函数,可以考虑使用 Promise 来处理异步请求。这样可以更清晰地组织代码,还能避免“回调地狱”的问题。这是原方法并不会在执行完http请求后......
  • C#异步和多线程的理解
    1.异步编程(AsynchronousProgramming)异步编程是通过非阻塞方式执行任务,通常适用于I/O密集型任务,例如文件读写、网络请求、数据库访问等。这类操作不需要占用大量CPU资源,而是等待外部资源(如网络或硬盘)响应。在C#中,异步编程使用async和await关键字来实现。异步方法会返......
  • CompletableFuture异步编排接口优化方案
    接口优化方案(1)程序本身,减少不必要的条件判断、循环(2)减少数据库的交互次数,以及每个sql查询的数据量(列数和行数越少越好)(3)提高sql的性能,通过建立合适的索引(4)使用java8的stream流提高集合的遍历操作的效率(5)引入缓存,从redis中加载数据的效率高于mysql(6)使用多线程异步......
  • 异步编程的利之Future模式深入解析(In Depth Analysis of Future Patterns)
     ......
  • playwright异步操作-多标签执行
    #作者:yancy#创建日期:2024/11/210:06#放屁:钱钱钱importasyncioimporttimefromplaywright.async_apiimportasync_playwrightfromplaywright.sync_apiimportsync_playwrightimportrandomasyncdefget_url(page,url):awaitpage.goto(url,timeout......
  • RabbitMQ的解耦、异步、削峰是什么?
    RabbitMQ在分布式系统和微服务架构中起到了重要的作用,其特性可以实现解耦、异步以及削峰,下面是对这三个概念的详细解释:1.解耦解耦是指使系统的不同组件间的依赖关系减少或消失。在使用RabbitMQ时,生产者(发送消息的组件)和消费者(接收和处理消息的组件)不直接交互,而是通过消息队......
  • 介绍使用@reduxjs/toolkit工具包发送异步请求最简便的方式
     1、安装@reduxjs/toolkit工具包pnpmi @reduxjs/toolkitreact-redux2、在src文件夹下新建store文件夹3、在store文件夹下新建index.js文件作为store的入口文件,其次再新建homeReducer.js文件4、homeReducer.js文件中写入以下代码//从@reduxjs/toolkit库中导入crea......
  • 高并发IPC通信实现:HarmonyOS中的异步调用与多线程处理
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在当今的移动应用开发领域,高并发通信场......
  • 深入解析C#异步编程:await 关键字背后的实现原理
    C#异步编程中await实现原理详解在C#中,async和await关键字用于编写异步代码。本文将详细介绍await的实现原理,包括状态机的生成、回调函数的注册和触发等关键步骤。1.异步方法的基本概念在C#中,async关键字标记一个方法为异步方法,而await关键字用于等待一个异步操作完......