在GTK4和 C中,如何正确等待web_view_javascript_finished() 返回?

前端开发 2026-07-08

我对这里记录的evaluate JavaScript设置实现了一个变体,目的是根据一个函数的结果返回一个字符串:https://webkitgtk.org/reference/webkitgtk/unstable/method.WebView.evaluate_javascript.html

下面是我的变体,请注意文档版本仅仅是打印,而我的版本把user_data设置为指向结果的指针。

web_view_javascript_finish() 运行是异步的,因此在获取值并继续处理流程之前,我需要等待它完成。

我了解过几种等待方法(信号量、互斥锁等),但先尝试一个最简单的方法,运行 while (!result) {},以便结果从NULL变成字符串值时,流程就会继续。

不过,如果去掉这一行,一切按预期工作,也许并不意外,printf("result element: %s\n",result); 打印为null,, 我认为是因为它在JavaScript完成之前就到了那里。

然而,在 while (!result) {}web_view_javascript_finished() 似乎根本没有运行(没有输出)。

在我迈向其他解决方案之前,我想先解决这个问题。

static void
web_view_javascript_finished (GObject      *object,
                              GAsyncResult *result,
                              gpointer      user_data)
{

    JSCValue               *value;
    GError                 *error = NULL;

    value = webkit_web_view_evaluate_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);

    if (!value) {
        g_warning ("1 Error running javascript: %s\n", error->message);
        g_error_free (error);
        return;
    }

    if (jsc_value_is_string (value)) {
        gchar        *str_value = jsc_value_to_string (value);
        JSCException *exception = jsc_context_get_exception (jsc_value_get_context (value));
        if (exception)
            g_warning ("2 Error running javascript: %s\n", jsc_exception_get_message (exception));
        else
            g_print ("3 Script result: %s\n", str_value);
        g_free (str_value);
    } else {
        g_warning ("4 Error running javascript: unexpected return value\n");
    }
    gchar        *str_value = jsc_value_to_string (value);
    g_print ("Script result: %s\n", str_value);
    user_data = str_value;
    g_print ("user_data result: %s\n", user_data
    g_object_unref (value);
}
static char *web_view_get_element_info (WebKitWebView *web_view,
                       const gchar   *uuid)
{
    gchar *script = g_strdup_printf ("el = window.document.getElementById('%s'); el_rect = el.getBoundingClientRect(); JSON.stringify(el_rect); ");
    char *result = NULL;
    webkit_web_view_evaluate_javascript (web_view, script, -1, NULL, NULL, NULL, web_view_javascript_finished, &result);
    while (!result) {}
    printf("result element: %s\n",result);
    return web_result;
    g_free (script);
}

解决方案

web_view_get_element_info()web_view_javascript_finished() 应该在同一个线程中运行。因此,如果你在其中一个中有一个while循环,只要它在运行,finished() 回调就永远不会执行。

你可以尝试的最小修改是使用 g_main_context_iteration()

所以,不是像

while (!result) {}

你可以尝试像下面这样

while (!result)
  g_main_context_iteration (NULL, TRUE);

在这样做时,在 finished() 回调中你始终需要把 result 设置为一个非NULL值(即使发生错误)。否则,它将会无限循环。

另一种建议——在许多基于GObject的项目中常用——是使用 GTask 来完成同样的事情。用 GTask,你会这样做:

#include <gio/gio.h>

static void
my_cb (GObject      *obj,
       GAsyncResult *result,
       gpointer      user_data)
{
  GTask *task = user_data;
  GError *error = NULL;
  gpointer ret;

  /* Finish the async function to get the result/error */
  ret = my_app_execute_finish (MY_APP (obj), result, &error);

  if (error)
    {
      g_task_return_error (task, error);
    }
  else
    {
      /* Do something with @ret, if needed */
      g_task_return_pointer (task, ret, NULL);
    }
}

void some_func(MyApp *self)
{
  g_autoptr(GTask) task = NULL;
  gpointer value;

  task = g_task_new (NULL, NULL, NULL, NULL);

  /* Run some Async function with appropriate arguments */
  my_app_execute_async (self, NULL, my_cb, task);

  while (!g_task_get_completed (task))
    g_main_context_iteration (NULL, TRUE);

  /* pass error argument, if needed */
  /* free @value as needed */
  value = g_task_propagate_pointer (task, NULL);
  /* Do something with @value */
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章