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

使用HTMLKit时,如何让异步HTML页面加载任务串行执行?

解决异步任务串行执行的几种方案

你的问题核心是要让异步任务串行执行——前一个页面加载完成后,再启动下一个任务,避免循环瞬间触发所有异步调用导致的覆盖问题。下面是三种实用的实现方式:

方案一:用Async/Await(iOS 15+ / macOS 12+ 推荐)

先把原有的getPage改造成支持异步等待的版本,利用Swift原生并发特性:

func getPage(_ url: URL) async throws -> String? {
    // 先加载目标URL到WebView
    try await webView.loadURL(url)
    // 页面加载完成后执行JS获取内容
    let result = try await webView.evaluateJavaScript("document.body.innerHTML")
    return result as? String
}

然后在异步函数里顺序等待每个任务完成:

func processLinksSequentially(_ links: [URL]) async {
    for link in links {
        do {
            if let pageContent = try await getPage(link) {
                // 处理当前页面内容
                print("完成处理:\(link)")
            }
        } catch {
            print("加载失败:\(link),错误:\(error)")
        }
    }
}

// 调用示例(比如在ViewController的viewDidLoad中)
Task {
    await processLinksSequentially(links)
}

注:如果webView.loadURL本身不支持Async/Await,可以用withCheckedThrowingContinuation封装回调版的加载方法,转成异步函数。

方案二:递归调用(兼容低版本系统)

如果项目需要支持iOS 15以下,递归是最直接的手动串行控制方式:

func processNextLink(from links: [URL], index: Int = 0) {
    guard index < links.count else {
        // 所有链接处理完毕
        return
    }
    let currentLink = links[index]
    
    // 先加载当前链接到WebView
    webView.load(URLRequest(url: currentLink))
    // 实际开发中必须依赖WKNavigationDelegate的didFinishNavigation确认页面加载完成,再执行JS
    webView.evaluateJavaScript("document.body.innerHTML") { [weak self] result, error in
        guard let self = self else { return }
        if let error = error {
            print("加载失败:\(currentLink),错误:\(error)")
        } else if let content = result as? String {
            // 处理当前页面内容
            print("完成处理:\(currentLink)")
        }
        // 递归触发下一个链接的加载
        self.processNextLink(from: links, index: index + 1)
    }
}

// 调用示例
processNextLink(from: links)

方案三:用OperationQueue串行队列

创建一个串行队列,限制并发数为1,确保任务按顺序执行:

let serialQueue = OperationQueue()
serialQueue.maxConcurrentOperationCount = 1 // 强制串行执行

func processLinksWithQueue(_ links: [URL]) {
    for link in links {
        serialQueue.addOperation { [weak self] in
            guard let self = self else { return }
            // 用信号量将异步操作转为同步等待
            let semaphore = DispatchSemaphore(value: 0)
            
            DispatchQueue.main.async {
                self.webView.load(URLRequest(url: link))
                self.webView.evaluateJavaScript("document.body.innerHTML") { result, error in
                    // 处理加载结果
                    if let error = error {
                        print("加载失败:\(link),错误:\(error)")
                    } else if let content = result as? String {
                        print("完成处理:\(link)")
                    }
                    semaphore.signal() // 任务完成,释放信号量
                }
            }
            
            semaphore.wait() // 等待当前任务完成,再执行下一个
        }
    }
}

// 调用示例
processLinksWithQueue(links)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 04:31:14