Передать дополнительный параметр в обратный вызов JSONP - PullRequest
11 голосов
/ 05 марта 2012

Для моего проекта мне нужно сделать несколько вызовов (удаленного) API, используя JSONP для обработки ответа API.Все вызовы используют одну и ту же функцию обратного вызова.Все вызовы генерируются динамически на стороне клиента с использованием JavaScript.

Проблема заключается в следующем: как передать дополнительные параметры этой функции обратного вызова, чтобы сообщить функции о параметрах запроса, которые я использовал.Так, например, в следующем примере мне нужна функция myCallback, чтобы узнать о id=123.

<script src="http://remote.host.com/api?id=123&jsonp=myCallback"></script>

Есть ли способ достичь этого без необходимости создания отдельной функции обратного вызова для каждого из моих вызовов?Ванильное решение JavaScript является предпочтительным.

РЕДАКТИРОВАТЬ :

После первых комментариев и ответов возникли следующие вопросы:

  • У меня нет никакого контроля над пультомсервер.Таким образом, добавление параметра в ответ не является вариантом.
  • Я запускаю несколько запросов одновременно, поэтому любая переменная для хранения моих параметров не решает проблему.
  • Я знаю, что могусоздать несколько обратных вызовов на лету и назначить их.Но вопрос в том, могу ли я как-то избежать этого.Это был бы мой запасной план, если не появятся другие решения.

Ответы [ 4 ]

10 голосов
/ 05 марта 2012

Ваши варианты следующие:

  1. Попросите сервер вставить идентификатор в ответ. Это самый чистый, но часто вы не можете изменить код сервера.
  2. Если вы можете гарантировать, что никогда не будет более одного вызова JSONP, вовлекающего вставку идентификатора одновременно, тогда вы можете просто вставить значение идентификатора в глобальную переменную, а когда вызывается обратный вызов, извлечь значение идентификатора из глобальной переменной. , Это просто, но хрупко, потому что если в процессе одновременно присутствует каждый вызов JSONP, включающий ID, они наступают друг на друга, и что-то не сработает.
  3. Создайте уникальное имя функции для каждого вызова JSONP и используйте замыкание функции, связанное с этим именем функции, для подключения идентификатора к обратному вызову.

Вот пример третьего варианта.

Вы можете использовать замыкание, чтобы отслеживать переменную для вас, но, поскольку вы можете иметь несколько вызовов JSON в полете одновременно, вы должны использовать динамически генерируемое глобально доступное имя функции, уникальное для каждого последующего JSONP. вызов. Это может работать так:

Предположим, ваша функция, генерирующая тег для JSONP, выглядит примерно так (вы заменяете все, что используете сейчас):

function doJSONP(url, callbackFuncName) {
   var fullURL = url + "&" + callbackFuncName;
   // generate the script tag here
}

Тогда у вас может быть другая функция, которая делает это:

// global var
var jsonpCallbacks = {cntr: 0};


function getDataForId(url, id, fn) {
    // create a globally unique function name
    var name = "fn" + jsonpCallbacks.cntr++;

    // put that function in a globally accessible place for JSONP to call
    jsonpCallbacks[name] = function() {
        // upon success, remove the name
        delete jsonpCallbacks[name];
        // now call the desired callback internally and pass it the id
        var args = Array.prototype.slice.call(arguments);
        args.unshift(id);
        fn.apply(this, args);
    }

    doJSONP(url, "jsonpCallbacks." + name);
}

Ваш основной код будет вызывать getDataForId(), и обратному вызову, переданному ему, будет передано значение идентификатора, подобное этому, с последующими другими аргументами, которые JSONP имеет для функции:

getDataForId(123, "http://remote.host.com/api?id=123", function(id, /* other args here*/) {
    // you can process the returned data here with id available as the argument
});
1 голос
/ 01 августа 2014

Есть более простой способ.Добавьте параметр к вашему URL после '?'.И получить к нему доступ в функции обратного вызова следующим образом.

var url = "yourURL";
    url += "?"+"yourparameter";
    $.jsonp({
        url: url,
        cache: true,
        callbackParameter: "callback",
        callback: "cb",
        success: onreceive,
        error: function () {
            console.log("data error");
        }
    });

И функции обратного вызова следующим образом

function onreceive(response,temp,k){
  var data = k.url.split("?");
  alert(data[1]);   //gives out your parameter
 }

Примечание. Параметр можно добавить в URL более удобным способом, еслиу вас уже есть другие параметры в URL.Я показал быстрое грязное решение здесь.

0 голосов
/ 02 мая 2013

Сейчас ему исполнился год, но я думаю, что jfriend00 был на правильном пути, хотя это проще, чем все это - используйте закрытие еще, просто, при указании обратного вызова добавьте параметр:

http://url.to.some.service? Callback = myFunc ('optA')

http://url.to.some.service? Callback = myFunc ('optB')

Затем используйте замыканиечтобы пройти через:

function myFunc (opt) {
    var myOpt = opt; // will be optA or optB

    return function (data) {
        if (opt == 'optA') {
            // do something with the data
        }
        else if (opt == 'optB') {
            // do something else with the data
        }
    }
}
0 голосов
/ 30 августа 2012

Поскольку я не могу комментировать, я должен написать ответ. Я следовал инструкциям jfriend00 для моего случая, но не получил фактический ответ от сервера в моем обратном вызове. Я закончил тем, что сделал:

var callbacks = {};

function doJsonCallWithExtraParams(url, id, renderCallBack) {
    var safeId = id.replace(/[\.\-]/g, "_");
    url = url + "?callback=callbacks." + safeId;
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);

    callbacks[safeId] = function() {
        delete callbacks[safeId];
        var data = arguments[0];
        var node = document.getElementById(id);
        if (data && data.status == "200" && data.value) {
            renderCallBack(data, node);
        }
        else {
            data.value = "(error)";
            renderCallBack(data, node);
        }

        document.body.removeChild(s);
    };

    document.body.appendChild(s);
}

По сути, я сжал goJSONP и getDataForUrl в 1 функцию, которая записывает тег сценария (и удаляет его позже), а также не использует функцию «unshift», так как это, похоже, удаляет ответ сервера из массива args. Поэтому я просто извлекаю данные и вызываю свой обратный вызов с доступными аргументами. Еще одно отличие состоит в том, что я повторно использую имена обратных вызовов, я мог бы изменить их на полностью уникальные имена со счетчиком.

На данный момент не хватает обработки тайм-аута. Я, вероятно, запустил таймер и проверил наличие функции обратного вызова. Если он существует, он не удалился, так что это тайм-аут, и я могу действовать соответственно.

...