You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift同步获取JS执行后页面完整HTML的实现问题

问题分析与解决方案

代码卡顿的核心原因

  • 执行时机错误:调用webView.load后立刻执行evaluateJavaScript,此时页面还未开始加载,且你的脚本仅注册了window.onload事件,并未立即返回HTML内容,导致evaluateJavaScript的回调永远不会触发,信号量一直处于等待状态,直接阻塞主线程造成卡顿。
  • 脚本逻辑无效:window.onload内部仅写了document.body.innerHTML,但该表达式未被返回,即便页面加载完成,也无法把HTML内容传递给evaluateJavaScript的回调。
  • WebView未挂载:WKWebView没有添加到视图层级中,部分场景下无法正常完成页面加载和JS执行流程。

修正后的代码

import WebKit

class InternetLoader: NSObject, WKNavigationDelegate {
    private let webView: WKWebView
    private var semaphore: DispatchSemaphore?
    private var resultHtml: String?
    
    override init() {
        let config = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: config)
        super.init()
        webView.navigationDelegate = self
        // 将WebView临时添加到窗口,确保能正常加载页面
        if let window = UIApplication.shared.windows.first {
            window.addSubview(webView)
        }
    }
    
    func getHTML(from url: URL) -> String {
        semaphore = DispatchSemaphore(value: 0)
        resultHtml = nil
        
        webView.load(URLRequest(url: url))
        
        semaphore!.wait()
        // 兜底处理,避免强制解包崩溃
        return resultHtml ?? ""
    }
    
    // 页面加载完成后执行JS获取完整HTML
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // 获取整个页面的完整HTML,而非仅body部分
        let script = "document.documentElement.outerHTML;"
        webView.evaluateJavaScript(script) { [weak self] result, error in
            guard let self = self else { return }
            if let error = error {
                print("执行JS出错:\(error.localizedDescription)")
            } else {
                self.resultHtml = result as? String
            }
            // 发送信号解除阻塞
            self.semaphore?.signal()
            self.semaphore = nil
            // 移除WebView,避免内存泄漏
            self.webView.removeFromSuperview()
        }
    }
    
    // 处理页面加载失败的情况,防止信号量一直等待
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        print("页面加载失败:\(error.localizedDescription)")
        semaphore?.signal()
        semaphore = nil
        webView.removeFromSuperview()
    }
}

// 使用示例
let il = InternetLoader()
let html = il.getHTML(from: URL(string: "https://stackoverflow.com/questions")!)

关键修正点

  • 实现WKNavigationDelegate,通过didFinish方法监听页面加载完成事件,确保在页面完全加载后再执行JS。
  • 将WKWebView添加到视图层级,保证页面能正常加载。
  • 直接执行获取完整HTML的JS脚本(document.documentElement.outerHTML),而非注册window.onload事件。
  • 增加页面加载失败的处理逻辑,避免信号量一直等待导致主线程阻塞。
  • 移除强制解包,增加兜底逻辑,避免崩溃。

内容的提问来源于stack exchange,提问作者Andrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:22:41