带有回调的 runJavaScript 不等待返回

Posted

技术标签:

【中文标题】带有回调的 runJavaScript 不等待返回【英文标题】:runJavaScript with callback does not wait for return 【发布时间】:2020-03-24 05:46:02 【问题描述】:

我刚刚开始使用 javascript 和 Qt,所以请耐心等待

我的问题是 runJavaScript 方法。我似乎无法让回调函数以延迟的返回值运行。例如,以下打印出None

js = '''
function returnHello()
    var i = 0;
    var wait = setInterval(function()  //arbitrary delay
        i++
        if(i>2)
            return('hello')
        
    , 10);

returnHello();
'''

def test(a):
    print(a)

mw.reviewer.web.page().runJavaScript(js, test)

我怀疑这与 javascript 如何异步运行有关,我尝试使用 javascript 回调方法,但如果返回值有任何延迟,Qt python 回调方法似乎总是接受undefined 默认javascript返回值。

我一直在网上寻找答案,所以任何帮助都会很棒!

【问题讨论】:

没有使用异步函数的返回值。 我想在 python 中打印 'hello',而不是 javascript - 我该怎么做 也许这个问题是相关的:***.com/questions/45230931/… 这是建议,但这似乎是一个不同的问题 - 他们所有的 javascript 都会立即返回值 除非有办法将 Python 回调传递给 runJavaScript,并让 JS 代码调用它,否则我认为你不走运。没有什么可以等待异步函数完成。 【参考方案1】:

说明:

您似乎不知道异步任务是如何工作的,异步函数不会返回内部信息,因为在评估分配时,任务尚未执行,也不会阻塞直到执行。例如,变量“wait”是一个定时器ID,用于取消定时器的执行。因此 runJavaScript 在这种情况下将不起作用。

解决方案:

一种可能的解决方案是使用Qt WebChannel,基于my previous answer我已经实现了以下解决方案:

import os
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets, QtWebChannel
from jinja2 import Template


class Element(QtCore.QObject):
    def __init__(self, name, parent=None):
        super(Element, self).__init__(parent)
        self._name = name

    @property
    def name(self):
        return self._name

    def script(self):
        raise NotImplementedError


class TestObject(Element):
    def script(self):
        _script = r"""
        function returnHello()
            var i = 0;
            var id_timer = setInterval(function()  //arbitrary delay
                i++
                if(i>2)
                    name.test('hello')
                
            , 10);
        
        returnHello();
        """
        return Template(_script).render(name=self.name)

    @QtCore.pyqtSlot(str)
    def test(self, a):
        print(a)


class WebEnginePage(QtWebEngineWidgets.QWebEnginePage):
    def __init__(self, *args, **kwargs):
        super(WebEnginePage, self).__init__(*args, **kwargs)
        self.loadFinished.connect(self.onLoadFinished)
        self._objects = []

    def add_object(self, obj):
        self._objects.append(obj)

    @QtCore.pyqtSlot(bool)
    def onLoadFinished(self, ok):
        if ok:
            self.load_qwebchannel()
            self.load_objects()

    def load_qwebchannel(self):
        file = QtCore.QFile(":/qtwebchannel/qwebchannel.js")
        if file.open(QtCore.QIODevice.ReadOnly):
            content = file.readAll()
            file.close()
            self.runJavaScript(content.data().decode())
        if self.webChannel() is None:
            channel = QtWebChannel.QWebChannel(self)
            self.setWebChannel(channel)

    def load_objects(self):
        if self.webChannel() is not None:
            objects = obj.name: obj for obj in self._objects
            self.webChannel().registerObjects(objects)
            _script = r"""
            % for obj in objects %
            var obj;
            % endfor %
            new QWebChannel(qt.webChannelTransport, function (channel) 
            % for obj in objects %
                obj = channel.objects.obj;
            % endfor %
            ); 
            """
            self.runJavaScript(Template(_script).render(objects=objects.keys()))
            for obj in self._objects:
                if isinstance(obj, Element):
                    self.runJavaScript(obj.script())


class WebPage(QtWebEngineWidgets.QWebEngineView):
    def __init__(self, parent=None):
        super().__init__(parent)

        page = WebEnginePage(self)
        self.setPage(page)

        test_object = TestObject("test_object", self)
        page.add_object(test_object)

        self.load(QtCore.QUrl("https://***.com/"))


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    web = WebPage()
    web.show()
    sys.exit(app.exec_())

【讨论】:

啊,是的,这很有意义 - 感谢您的解释和示例

以上是关于带有回调的 runJavaScript 不等待返回的主要内容,如果未能解决你的问题,请参考以下文章

带有回调的AngularJS动画,等待下一个动画开始

JavaScript函数等待回调返回值[重复]

如何等待异步方法的回调返回值?

如何等待异步方法的回调返回值?

Express 中的回调与等待性能

如何等待 requestLocationUpdates() 回调意图完成?