1

Callback Closure

Тема: Callback Closure

Hallo

I need a ‘for’ loop to build an array of all the units with custom sensor values, which means more than one callback is scheduled which is not completed in the same loop iteration.  I know I need some sort of ‘callback closure’ here, but I don’t know how to implement it with the MessagesLoader.loadInterval method.  Could you please assist?

My code below:
function loadMessages(units) {
    var sess = wialon.core.Session.getInstance();
    var to = sess.getServerTime(); // get ServerTime
    var from = to - 300; // 5 minutes
    var ml = sess.getMessagesLoader();
    for (var i = 0; i < units.length; i++) {
        var unitId = units(i).unitId;
    const temp = ml.loadInterval(unitId, from, to, 0, 0, 10,
            function (code, data) { // loadInterval callback

               
                if (code) { msg(wialon.core.Errors.getErrorText(code)); return; } // exit if error code
                else {

                    let custSensorValues = [];
                    for (var i = data.messages.length - 1; i > 0; i--) { // get last received message with values
                        if (data.messages(i).p.data_type === "E6") { // E6 = custom sensor values??
                            let custSensorValue = {};
                            custSensorValue.t11p = (data.messages(i).p.t11_pressure * 0.0689475729).toFixed(2);
                            custSensorValue.t14p = (data.messages(i).p.t14_pressure * 0.0689475729).toFixed(2);
                            custSensorValues.push(custSensorValue);
                            units(i).custSensorValues = custSensorValues;
                        }
                    }
                }
               
            }
        );
    }
}
Thank you in advance.

2

Callback Closure

Re: Callback Closure

Easiest way to execute async operations in sequental order is to use Promises.

I wrapped messageLoader.loadInterval with function, that returns promise, added async to loadMessages and then we can use await on loadIntervalAsync to wait for request finish:

const API_ERROR = 'API_ERROR';

main().catch((error) => {
    if (error.type === API_ERROR) {
        let reason = error.fullError && error.fullError.reason;
        msg(
            wialon.core.Errors.getErrorText(error.code) +
                (reason ? ' ' + reason : ''),
        );
    } else {
        msg('See more detailed error in console: ' + error);
        console.error(error);
    }
});

async function main() {
    await loadMessages(units);

    // There you can use `custSensorValues`
}

async function loadMessages(units) {
    var sess = wialon.core.Session.getInstance();
    var timeTo = sess.getServerTime(); // get ServerTime
    var timeFrom = timeTo - 300; // 5 minutes
    var ml = sess.getMessagesLoader();

    for (var i = 0; i < units.length; i++) {
        var unitId = units[i].unitId;

        let data = await loadIntervalAsync(ml, {
            unitId,
            timeFrom,
            timeTo,
            loadCount: 10,
        });

        let custSensorValues = [];
        for (var i = data.messages.length - 1; i >= 0; i--) {
            // get last received message with values
            if (data.messages[i].p.data_type === 'E6') {
                // E6 = custom sensor values??
                let custSensorValue = {};
                custSensorValue.t11p = (
                    data.messages[i].p.t11_pressure * 0.0689475729
                ).toFixed(2);
                custSensorValue.t14p = (
                    data.messages[i].p.t14_pressure * 0.0689475729
                ).toFixed(2);
                custSensorValues.push(custSensorValue);
                units[i].custSensorValues = custSensorValues;
            }
        }
    }
}

function loadIntervalAsync(messageLoader, options) {
    let {
        itemId,
        timeFrom,
        timeTo,
        flags = 0,
        flagsMask = 0,
        loadCount,
    } = options;

    return new Promise((resolve, reject) => {
        messageLoader.loadInterval(
            itemId,
            timeFrom,
            timeTo,
            flags,
            flagsMask,
            loadCount,
            (error, result) => {
                if (error) {
                    reject({ type: API_ERROR, code: error, fullError: result });
                    return;
                }

                resolve(result);
            },
        );
    });
}

Also I used i >= 0, not sure that you need it, but in your code first message was not processed.

3

Callback Closure

Re: Callback Closure

Many thanks!  Exactly what I needed!

4

Callback Closure

Re: Callback Closure

"Also I used i >= 0, not sure that you need it, but in your code first message was not processed."

I actually only need the very last message with custom sensor values/data. Is the way I did it the best/correct way to do it?