Как мы можем отправить большие объекты из фона на активную вкладку в CrossRider?

Мы используем CrossRider для разработки расширения для Internet Explorer. Наше расширение имеет код, который отправляет сообщение фону, а фон отправляет ответ и вызывает функцию обратного вызова. Это работает на моем компьютере с Internet Explorer 11, но на компьютере моего друга Тома (также с Internet Explorer 11) это не работает - обратный вызов не вызывается на его компьютере. В чем проблема и как мы можем исправить это для работы на любом компьютере? Вот соответствующий код:

_base.js:

alert("[ContentBase::getData] >>>>>"); // This happens in any computer.
var request = {command: 'get', webmail: thisObj.mContentType, param: param, type: type, contentType: contentType};
thisObj.sendRequest(request, function(response) {
    alert("[ContentBase::getData] received data >>>>>"); // This doesn't happen in Tom's computer.
    if (typeof(callback) === 'function') {
        callback(response);
    }
});

utils.js:

this.sendRequest = function(request, callback) {
    if (typeof(callback) !== 'function') {
        callback = function(response) {};
    }

    switch (Sys.platform) {
        case 'crossrider':
            var message = {request: request, message_id: Math.floor((Math.random() * 900000000000000) + 100000000000000)};
            if (typeof thisObj.mCallbackMap === 'undefined') {
                thisObj.mCallbackMap = {};
                appAPI.message.addListener({channel: "message_from_background"}, function(message) {
                    if (typeof thisObj.mCallbackMap[message.message_id] === 'function') {
                        thisObj.mCallbackMap[message.message_id](message.response);
                        delete thisObj.mCallbackMap[message.message_id];
                    }
                });
            }

            (function(callback_inner) {
                thisObj.mCallbackMap[message.message_id] = function(response) {
                    if (typeof(callback_inner) === 'function') {
                        callback_inner(response);
                    }
                };
            })(callback);

            appAPI.message.toBackground(message, {channel: "message_to_background"});
            break;
    }
};

background.js:

appAPI.message.addListener({channel: "message_to_background"}, function(params) {
    MsgHandler.handle(params.request, undefined, function(responseParams) {
        appAPI.message.toActiveTab({'message_id': params.message_id, 'response': responseParams}, {channel: "message_from_background"});
    });
});

msgHandler.js:

this.handle = function(request, sender, callback_out) {
    function callback(response) {
        if (typeof(callback_out) === 'function') {
            callback_out(response);
        }
    }

    switch (request.command) {
        case "get":
            switch (request.type) {
                case "all":
                    var data = Controller.getData();
                    alert("[MsgHandler::handle] get / all, data.length = " + JSON.stringify(data).length + ", data = " + JSON.stringify(data)); // This happens in any computer.
                    callback({data: data});
                    break;
            }
            break;
    }
    return true;    //this return is needed for chrome in order to execute callbacks

};

Sys.platform всегда равно "кроссрайдер".

Обновление: когда JSON.stringify(data).length было 5981 байт, сообщение было получено, но когда оно было 10157 байт, сообщение не было получено активной вкладкой (с appAPI.message.toActiveTab). Каков предел размера объектов, отправляемых из фона, и как мы можем отправлять большие объекты на вкладки (до 100 КБ)?

Наш ID расширения 43889. Я использую Internet Explorer 11, но это расширение должно работать на всех версиях Internet Explorer.

Кстати, другие звонки из фона работают, только этот конкретный звонок не работает. Мы пробовали несколько раз на компьютере Тома, и он никогда не работал.

Редактировать: я создал простое расширение с той же проблемой, идентификатор расширения - 67708. Вот код простого расширения:

extension.js:

appAPI.ready(function($) {
    alert("appAPI.platform = " + appAPI.platform);
    if (appAPI.platform === 'IE') {

        appAPI.message.addListener({channel: "message_from_background"}, function(message) {
            alert("message_from_background received, message_id = " + message.message_id + ", message.length = " + JSON.stringify(message).length + ", message = " + JSON.stringify(message));
        });

        appAPI.message.toBackground({}, {channel: "init_background"});
    }
});

background.js:

appAPI.ready(function($) {
    alert("appAPI.platform = " + appAPI.platform);
    if (appAPI.platform === 'IE') {
        var ready = false;
        appAPI.message.addListener({channel: "init_background"}, function(params) {
            if (ready === false) {
                alert('init_background, ready = ' + ready);
                ready = true;

                var message_id = 9999;
                var responseParams = {'a': 1, 'b': 2, 'c': 3};
                alert('sending message to active tab, message_id = ' + message_id + ', responseParams.length = ' + JSON.stringify(responseParams).length);
                appAPI.message.toActiveTab({'message_id': message_id, 'response': responseParams}, {channel: "message_from_background"});

                var message_id = 9998;
                var responseParams = {
                    // a big object
                };
                alert('sending message to active tab, message_id = ' + message_id + ', responseParams.length = ' + JSON.stringify(responseParams).length);
                appAPI.message.toActiveTab({'message_id': message_id, 'response': responseParams}, {channel: "message_from_background"});

                alert(appAPI.platform);
            }
        });
    }
});

когда JSON.stringify(responseParams).length равным 19 байтам, сообщение принимается активной вкладкой, но когда оно составляет 10576 байт, сообщение не принимается.

2 ответа

Решение

Хорошо, поскольку размер объектов в сообщениях ограничен 8000 байт, я разделил объекты на пакеты размером до 5000 байт. Вот код моего расширения:

utils.js:

this.sendRequest = function(request, callback) {
    if (typeof(callback) !== 'function') {
        callback = function(response) {};
    }

    switch (Sys.platform) {
        case 'crossrider':
            var message = {request: request, message_id: Math.floor((Math.random() * 900000000000000) + 100000000000000)};
            if (typeof thisObj.mCallbackMap === 'undefined') {
                thisObj.mCallbackMap = {};
                thisObj.mResponseObject = {};
                appAPI.message.addListener({channel: "message_from_background"}, function(message) {
                    alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", checking message...");
                    if ((typeof(message) === 'object') && (!(message === null)) && (typeof(message['divided_object_length']) === 'number')) {
                        if (typeof thisObj.mResponseObject[message.message_id] === 'undefined') {
                            thisObj.mResponseObject[message.message_id] = {}
                        }
                        var limit = message['divided_object_length'];
                        var packet_id = message['packet_id'];
                        var packet = message['packet'];
                        alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", limit = " + limit + ", packet_id = " + packet_id + "...");
                        thisObj.mResponseObject[message.message_id]['packet_' + packet_id] = packet;
                        var message_is_ready = true;
                        for (var packet_id = 0; packet_id < limit; packet_id++) {
                            if (typeof thisObj.mResponseObject[message.message_id]['packet_' + packet_id] === 'undefined') {
                                var message_is_ready = false;
                            }
                        }
                        if (message_is_ready) {
                            delete message['divided_object_length'];
                            delete message['packet_id'];
                            delete message['packet'];
                            var s = '';
                            for (var packet_id = 0; packet_id < limit; packet_id++) {
                                s += thisObj.mResponseObject[message.message_id]['packet_' + packet_id];
                            }
                            message.response = JSON.parse(s);
                            delete thisObj.mResponseObject[message.message_id];
                        }
                    } else {
                        var message_is_ready = true;
                    }
                    alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", message_is_ready = " + message_is_ready + "...");
                    if (message_is_ready) {
                        if (typeof thisObj.mCallbackMap[message.message_id] === 'function') {
                            alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", calling function...");
                            thisObj.mCallbackMap[message.message_id](message.response);
                            delete thisObj.mCallbackMap[message.message_id];
                        }
                    }
                });
            }

            (function(callback_inner) {
                thisObj.mCallbackMap[message.message_id] = function(response) {
                    alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", checking inner function...");
                    if (typeof(callback_inner) === 'function') {
                        alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", calling inner function...");
                        callback_inner(response);
                    }
                };
            })(callback);

            appAPI.message.toBackground(message, {channel: "message_to_background"});
            break;
    }
};

background.js:

appAPI.message.addListener({channel: "message_to_background"}, function(params) {
    alert("background.js :: message received, params = " + JSON.stringify(params));

    MsgHandler.handle(params.request, undefined, function(responseParams) {
        alert("background.js :: message received callback, message_id = " + params.message_id + ", sending response.");

        var s = JSON.stringify(responseParams);
        if ((typeof(s) === "string") && (s.length > 5000)) {
            var limit = Math.floor((s.length - 1) / 5000) + 1;
            alert("background.js :: message received callback, message_id = " + params.message_id + ", sending response, s.length = " + s.length + ", limit = " + limit + ".");
            for (var packet_id = 0; packet_id < limit; packet_id++) {
                var message = {};
                message['divided_object_length'] = limit;
                message['message_id'] = params.message_id;
                message['packet_id'] = packet_id;
                message['packet'] = s.substr(packet_id * 5000, 5000);
                appAPI.message.toActiveTab(message, {channel: "message_from_background"});
            }
        } else {
            appAPI.message.toActiveTab({'message_id': params.message_id, 'response': responseParams}, {channel: "message_from_background"});
        }
    });
});

Остальная часть кода такая же, как и в моем вопросе (оповещения предназначены только для отладки, мы удаляем их в производстве).

@Uri Спасибо за обновленный вопрос.

В свете новой информации я хотел бы обратить ваше внимание на примечание в документации ( appAP.message) об ограничениях Internet Explorer:

Сообщения преобразуются в строки JSON перед отправкой. Из-за ограничений в Internet Explorer максимальная длина строки JSON составляет 8000 байт (8 КБ).

Вы можете обойти эту проблему, сохранив данные в локальной базе данных и отправив короткое сообщение на активную вкладку, чтобы активировать ее для чтения данных. Ниже приведен упрощенный пример потока:

background.js:

appAPI.ready(function($) {
  appAPI.db.async.set(
    'my-data',
    myData,
    appAPI.time.minutesFromNow(1),
    function() {
      appAPI.message.toActiveTab({type: 'get-data'});
    }
  );
});

extension.js:

appAPI.ready(function($) {
  appAPI.message.addListener(function(msg) {
    if (msg.type === 'get-data') {
      appAPI.db.async.get('my-data', function(data) {
        // do something with data
      });
    }
  });
});

[Раскрытие информации: я сотрудник Crossrider]

Другие вопросы по тегам