Pregunta

Ive brought this up with other developers, and they say while there is no obvious way forward, it seems that they all have an idea of how to go about it.

Is there any way I can implement signals and slots javascript and or typescript? I want to get as close to this functionality as possible: https://doc.qt.io/qt-5/signalsandslots.html

And a code example to demonstrate what I mean:

#include <QObject>
class Label : public QObject
{
    Q_OBJECT

public:
    Label( QObject *parent=nullptr );
    QString label()
    {
        return removePlaceholders(m_Label);
    } 
    void setLabel(QString label)
    {
        m_Label = label;
        emit labelChanged(label);
    }

signals:
    void labelChanged(QString label);

private:
    QString m_Label;
};

which can be utilized like so:

Label label;

QEventLoop waitForLabel;
connect(&label, &Label::labelChanged, &waitForLabel, &QEventLoop::quit);
waitForLabel.exec; // Now the thread can not move past this point, 
// will have to wait for the signal Label::labelChanged to be emitted
// from the Label::setLabel function in the label object.
¿Fue útil?

Solución

Signals and slots are an implementation of an event system or of the observer pattern. Those are not tied to C++ but can be implemented in any language. Unfortunately, naive implementations of the observer pattern tend to lead to memory leaks.

The gist is that signals are not actually magic but:

  • a list of callbacks (“slots“) that shall be called when an event occurs.
  • a method to trigger the event, which means calling each callback.

Qt introduced an explicit language-level signal/slots mechanism because C++ was originally really bad at stuff like callbacks.

Javascript does not have this difficulty because you can just use functions. Instead of connect(source, &A::signal, handler, &Some::slot) you might just write source.onSignal.push(() => handler.slot()).

It is also debatable whether registering per-object event handlers is a sensible approach to structure event-driven programs. An alternative is that a central broker tracks dependencies between event-driven code (sometimes called a Reactor). There are also approaches such as functional-reactive programming that strive to be more declarative. Often, the motivation for event-based programming is an asynchronous program, but here JS offers a better approach with its async/await syntax. JavaScript has an unusually rich ecosystem of different event system implementations.

Otros consejos

For those interested, this is what I ended up implementing as my basic class structure

    /* Boiler Plate */
    // Getters
    public table() : string { return this.m_Table; }

    // Setters
    public setTable(table: string) { this.m_Table = table; this.tableChanged(table); }

    // Signals
    private tableChanged(table: string): void {this.onTableChanged.forEach(f=>f(table));}

    // Slots
    public onTableChanged: Array<(table: string) => void> = new Array;

    // Member variables
    private m_Table: string;
let psql = new QPostgreSQL( "db_qpoll", "/*/*/*/*/*][/" );
psql.onTableChanged.push((s) => console.log(s); ); // You can toss functions in here. 
psql.setTable( '"Question"."Questions"' );

or in picture form : enter image description here

The only thing I wish I had now, are text preprocessor macros to simplify everything here.

Licenciado bajo: CC-BY-SA con atribución
scroll top