Background: I am working in a project that requires the following: the user can write commands to perform some mathematical operations with internal variables of the main program (a GUI written in Qt/C++).
My approach is a text box where the user can write the commands/scripts in JavaScript and then Qt evaluates that code. To that end I am using QJSEngine
The Problem: The computation speed of JavaScript is very bad/slow.
For example, we have a just a GUI with two text boxes (QTextEdit) and one button. In one textbox the user writes the JavaScript code and when the button is pressed it is evaluated and the result appears in the other textbox.
As an example of the bad performance, when the user writes this trivial JavaScript code the computer spends ~3 seconds to show the answer:
var X = [];
for (var i=0 ; i < 934600 ; ++i )
{
X[i] = i;
}
X[120]
On the other hand, if the same operation is performed in Qt/C++, it is "instantaneous":
QVector<double> myVec;
for(int i=0; i < 934600; ++i)
{
myVec.append(i);
}
qDebug() << myVec.value(120);
I know that JavaScript is a interpreted language, but is it normal this performance?
Here you have a small Qt sample program (pr_Parser) to show this problem. I have tested this in Qt Creator 4.0.1. With Qt 5.7 MSVC2013 64 bits.
Thank you.
QT += core gui qml
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = pr_Parser
TEMPLATE = app
CONFIG += c++11
SOURCES += main.cpp\
CMainWindow.cpp
HEADERS += CMainWindow.h
#include "CMainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CMainWindow w;
w.show();
return a.exec();
}
#include <QMainWindow>
class QPlainTextEdit;
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
CMainWindow(QWidget *parent = 0);
~CMainWindow();
private:
QPlainTextEdit *m_p_myScriptWindow;
QPlainTextEdit *m_p_myResultWindow;
private slots:
void slot_ExecuteScript();
};
#include "CMainWindow.h"
#include <QtWidgets>
#include <QJSEngine>
CMainWindow::CMainWindow(QWidget *parent)
: QMainWindow(parent)
{
QWidget *window = new QWidget(this);
setCentralWidget(window);
QString sampleScript = "var X = [];";
sampleScript.append("for (var i=0 ; i < 934600 ; ++i ){X[i]=i;}");
sampleScript.append("X[120]");
m_p_myScriptWindow = new QPlainTextEdit(sampleScript, this);
m_p_myResultWindow = new QPlainTextEdit(this);
QPushButton *myButton = new QPushButton("Execute", this);
QVBoxLayout *myLayout = new QVBoxLayout(this);
myLayout->addWidget(m_p_myScriptWindow);
myLayout->addWidget(myButton);
myLayout->addWidget(m_p_myResultWindow);
window->setLayout(myLayout);
connect(myButton, SIGNAL(clicked()), this, SLOT(slot_ExecuteScript()));
}
CMainWindow::~CMainWindow(){}
void CMainWindow::slot_ExecuteScript()
{
QJSEngine myEngine;
QString myScript = m_p_myScriptWindow->toPlainText();
QJSValue myValue = myEngine.evaluate(myScript);
if(myValue.isError())
{
m_p_myResultWindow->setPlainText(myValue.property("message").toString());
}
else
{
m_p_myResultWindow->setPlainText(myValue.toString());
}
// This code is "instanteneous"
// QVector<double> myVec;
// for(int i=0; i < 934600; ++i) {myVec.append(i);}
// m_p_myResultWindow->setPlainText(QString::number(myVec.value(120)));
}
I have found the answer.
The problem was that I was compiling it in Debug mode. In release mode is 10 times faster.
Measured times (with QElapsedTimer) executing it several times:
JavaScript script:
The same "for" in native Qt/C++: