【问题标题】:How can I get this JSONP call to return a value?如何让这个 JSONP 调用返回一个值?
【发布时间】:2013-07-02 03:32:44
【问题描述】:

以下函数的目的是访问雅虎服务器上的脚本并查找实时货币兑换率,该汇率稍后将用于处理客户的购买。

我能够访问 JavaScript 警报中的费率,但我似乎无法将它们返回到最初调用 getRate() 函数的 Jquery 方法。

我在parseExchangeRate() 函数的末尾尝试了一个标准的return rate;,但它不起作用。我也尝试将rate 设置为parseExchangeRate() 中的全局变量,但这也不起作用。

function getRate(from, to) {

    var script = document.createElement('script');

    script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
    document.body.appendChild(script);

}

function parseExchangeRate(data) {

    var name = data.query.results.row.name;
    rate = parseFloat(data.query.results.row.rate, 10);

    alert("Exchange rate " + name + " is " + rate);

}

$(function() {

    getRate('USD', 'PHP');
    xRatePHP = rate;

    /* Do stuff with rate */

});

当我尝试在 Jquery 函数中访问它时,Firebug 告诉我 rate 未定义。

我尝试的另一件事是将http请求的最后一个参数设置为callback=rate=parseExchangeRate,这(不足为奇)也不起作用。

更新

@Relfor 解决了最初的问题,即 rate 没有正确声明为全局范围内的全局变量。我解决了这个问题,然后发现了另一个问题,有些人也在下面发现了这个问题,即在调用 getRate() 之后(更新变量 rate 可能需要大约 2000 毫秒),脚本立即继续运行,而无需等待 @987654333 @ 将被更新并使用费率,无论它是否准备好。

我尝试使用window.setInterval 来创建延迟来解决这个问题,当我注意到即使我已经接受了@Relfor 的回答,他们仍然在线程中活动,所以我更喜欢把它带回来,这样当我们开始工作时,其他人可以从解决方案中受益。

有一个最终(我希望 - 最终!) 问题,那就是为了简化发布的原始问题,我没有透露我实际上试图从雅虎! (可能还有更多计划),因此,我在循环中调用getRate(),如下所示:

function getRate(from, to) {

    var script = document.createElement('script');

    script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
    document.body.appendChild(script);

}

function parseExchangeRate(data) {

    var name = data.query.results.row.name;
    rate = parseFloat(data.query.results.row.rate, 10);

}

var rate = 1.00;
var timer;
var q;
var xRatePHP, xRateGBP;
$(function() {

    function getTheRates() {

        var rateArr = new Array('PHP','GBP');

        for (var x=0; x < rateArr.length; x++) {
            getRate('USD', rateArr[x]);

            q = 0;
            timer = window.setInterval(function(){manageTimer(rateArr[x])},100);

        }
    }

    function manageTimer(c) {

        if (rate != 1) {

            window.clearInterval(timer);

            /* Note that 'c' is undefined according to 'alert' below,
             * so this next line is not working correctly.
             */
            eval("xRate"+c+" = rate;"); 


            alert(c + " = " + rate); // displays 'undefined 43.543'

            rate = 1.00;

        }

        q++;

        if (q > 30 ) {

            window.clearInterval(timer);

            // added below because above isn't working (but neither does this!)
            timer = '';
            alert(c+' timeout'); // 'c' is undefined according to alert ???
            q = 0;

        }

    }

    getTheRates();

    /* Do stuff with the rates */

});

有人建议我将/* Do stuff with the rates */ 移动到函数parseExchangeRate() 内部,但不确定该建议是否仍然有效,因为我透露了有关在循环中调用getRate() 的信息?

更新 3(替换更新 2)

我在这里创建了一个 JSbin:http://jsbin.com/udikas/3/edit,除了这两个问题之外,它似乎正在工作:

1) 超时机制似乎不起作用。

2) 在第 33 行这一行 alert('start timer (' + x +')'); 没有它,计时器似乎没有启动!我不知道为什么,但我不能把那条线留在里面。

【问题讨论】:

  • 在使用之前不要给它赋值。由于这是一个非局部变量,它应该是一个 ReferenceError。但是,似乎缺少上下文,并且parseExchangeRate 可能是 AJAX 调用的回调。在这种情况下,请记住这一点:回调可能异步发生
  • 放弃 URL 的“回调”参数并简单地使用 AJAX 请求会不会更好,该请求会返回 JSON,然后您可以将其传递给您需要的任何函数。
  • @Paul 我在使用rate 之前没有赋值,但我现在只是尝试过,没有任何区别。这其中不涉及 AJAX。
  • @mibbler AJAX 是否可以跨域工作?我不认为它会。
  • 我需要在调用函数之前在 Jquery 方法中初始化全局变量,而不是从内部初始化,这是我尝试过的。 @Paul 你是对的,但我需要下面 Relfor 的帮助来弄清楚该放在哪里。

标签: javascript jquery callback return jsonp


【解决方案1】:

变量rate尚未定义

$(function() {

    getRate('USD', 'PHP');
    xRatePHP = rate;

    /* Do stuff with rate */

});

在研究了您的代码后,parseExchange(data) 函数中似乎将速率定义为

function parseExchangeRate(data) {

    var name = data.query.results.row.name;
    rate = parseFloat(data.query.results.row.rate, 10);

    alert("Exchange rate " + name + " is " + rate);

}

如果您希望从函数命名空间访问速率而不从内部声明它们,则必须在全局命名空间中指定速率,该命名空间位于任何函数或循环之外。

编辑:命名空间问题已解决,我给出的答案已被接受,但是我想在此处添加有关您正在处理的代码的详细信息。它取自这里的要点:https://gist.github.com/henrik/265014

我们这里处理的是 JSONP

parseExchangeRate 存在的原因及其上下文乍一看似乎很神秘,尽管它的存在是您的 JSONP 请求和响应返回的数据之间的主要连接。

如果您仔细查看请求:

http://query.yahooapis.com/v1/public/yql?
q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2F
download.finance.yahoo.com%2Fd%2F
quotes%3Fs%3DUSDPHP%253DX%26f%3Dl1n'%20and%20
columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate

(为了便于阅读,我将链接分成多行)
仔细看url的最后一段:callback=parseExchangeRate
这是连接,当 JSONP 请求完成时会调用 parseExchangeRate。

那么为什么它不起作用呢?

让我再次显示代码:

$(function() {

    getRate('USD', 'PHP');
    xRatePHP = rate;

    /* Do stuff with rate */

});

我们应该分手:

  • getRate('USD', 'PHP') 负责使用“USD”和“PHP”各自的货币类型加载 JSONP
  • xRatePHP = rate 将右侧的rate 分配给xRatePHP但是这条线给我们带来了问题!我们的控制台朋友告诉我们 rate 未定义!

真相:mr.console 没有说谎,rate 实际上是未定义的,然而mr.console 没有你给出任何进一步的命令 strong> 片刻之后,如果再次询问将回复 rate 实际上已定义。这是魔法吗?

实际发生的情况是在您从这条线开始的时间之间

getRate('USD', 'PHP');

xRatePHP = rate;

来自 mr.yahoo 的 JSONP 响应尚未返回,这就是为什么在发出 xRatePHP = raterate 似乎未定义。

硬编码解决方案
让我们在使用 rate 之前硬编码一段代码等待的时间,以便我们知道 mr.yahoo 做出了回应,setTimeout 将在这里帮助我们:

getRate('USD', 'PHP');
setTimeout(function(){alert(rate)}, 2000);

现在一切正常!查看演示:http://jsbin.com/udikas/1/edit

软代码
你有没有考虑过雅虎先生的响应时间超过 2000 毫秒的情况?或者甚至比这还少? (雅虎相当快!)让我们改用不同的方法,这将让我们使用rate 精确时刻,我们用parseExchangeRate 计算它

为此,我们必须添加来自parseExchangeRate 的回调:

function parseExchangeRate(data) {

    var name = data.query.results.row.name;
    rate = parseFloat(data.query.results.row.rate, 10);

    alert("Exchange rate " + name + " is " + rate);

}

function parseExchangeRate(data) {

    var name = data.query.results.row.name;
    rate = parseFloat(data.query.results.row.rate, 10);

    alert("Exchange rate " + name + " is " + rate);
    gotTheRate(rate)

}

然后改变

$(function() {

    getRate('USD', 'PHP');
    alert(rate)

});

function gotTheRate(rate){
    alert(rate);
  }

$(function() {

    getRate('USD', 'PHP');
      
});

可以在http://jsbin.com/udikas/2/edit找到一个演示

多次回调(响应问题更新)

记住硬编码 setTimeouts 并不好玩,所以让我们从您的代码中删除 manageTimerq 和其他此类元素,取而代之的是:

function getRate(from, to) {

    var script = document.createElement('script');

    script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
    document.body.appendChild(script);

}

function parseExchangeRate(data) {

    var name = data.query.results.row.name;
  
    rateDict[name.match(/USD to ([\w]*)/)[1]] = parseFloat(data.query.results.row.rate, 10);
    total_responses++;
  if (total_responses === rateArr.length){
    for (var k in rateDict){
        alert("USD to " + k + " is " + rateDict[k]);
    }
  }
}

var rate = 1.00;
var timer;
var q;
var rateArr = new Array('PHP','GBP')
var total_responses = 0;
var rateDict = {};

$(function() {

    function getTheRates() {


        for (var x=0; x < rateArr.length; x++) {

            getRate('USD', rateArr[x]);

        }
    }

    getTheRates();
  

}); 

http://jsbin.com/udikas/4/edit

-Relfor

【讨论】:

  • OP 正在使用 JSONP,getRate 从 Yahoo 向页面添加 javascript,完成后调用函数 parseExchangeRate,因为 OP 希望在调用 getRate 后直接访问 rate 变量他得到一个错误。这是因为脚本还没有加载,回调parseExchangeRate 还没有被回调。 OP 需要在 parseExchangeRate 函数中对 rate 做一些事情。
  • 准确来说,代码是不完整的,rate 需要在命名空间中存在才可以使用,在这种情况下它不是。在 JSONP 加载之后,我假设 rate 将通过调用 parseExchangeRate 来计算,因此可用于 xRatePHP 或任何其他要分配 rate 的变量。
  • 异步执行。 XratePHP 在调用getRate 后立即设置为 rate 的值,但 getRate 尚未调用 parseExchangeRate。定义 rate 不会帮助 XratePHP 设置一个虚假的值,因为尚未调用 parseExchangeRate 来将其设置为从 Yahoo 返回的实际值。
  • +1 感谢您继续参与。我已经用其他/更新的信息更新了我的帖子。谢谢@Relfor。
  • 刚刚再次更新了我的原始帖子,提供了有关正在发生的事情的更多信息。现在将仔细研究我如何将您的上述建议与我的多个费率相结合。顺便说一句,谢谢你的 jsbin - 很好的接触。
【解决方案2】:

你应该重新排序你的代码流:

function getRate(from, to) {
    var script = document.createElement('script');
    script.setAttribute('src', "http://query.yahooapis.com/v1/public/yql?q=select%20rate%2Cname%20from%20csv%20where%20url%3D'http%3A%2F%2Fdownload.finance.yahoo.com%2Fd%2Fquotes%3Fs%3D"+from+to+"%253DX%26f%3Dl1n'%20and%20columns%3D'rate%2Cname'&format=json&callback=parseExchangeRate");
    document.body.appendChild(script);
}
function parseExchangeRate(data) {
    var name = data.query.results.row.name;
    var rate = parseFloat(data.query.results.row.rate, 10);
    alert("Exchange rate " + name + " is " + rate);
    xRatePHP = rate;
    /* Do stuff with rate */
}
$(function() {
    getRate('USD', 'PHP');
    // rate is not yet available here, so don't do anything with it
});

【讨论】:

    【解决方案3】:

    试一下:

    var rate = 0;
    

    在您的代码之上。这将修复错误。 然后你必须考虑,如果你得到 0 可能你在错误的时间读取变量,在它被填充之前。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-16
      • 2015-03-08
      • 2013-02-24
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      • 1970-01-01
      相关资源
      最近更新 更多