Javascript 从承诺返回值

Javascript 从承诺返回值,javascript,jquery,ajax,promise,q,Javascript,Jquery,Ajax,Promise,Q,我想使用如下承诺调用Google地图地理编码API: function makeGeoCodingRequest(address,bounds) { /* Input parameters: address:a string bounds: an object of class google.maps.LatLngBounds(southWest,northEast) This will return a

我想使用如下承诺调用Google地图地理编码API:

function makeGeoCodingRequest(address,bounds)
{
    /*
        Input parameters:
            address:a string
            bounds: an object of class google.maps.LatLngBounds(southWest,northEast)

        This will return a set of locations from the google geocoding library for the given query
     */
    var url="https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=AIzaSyD9GBloPC20X-1kWRo7sm_0z5xvCiaSd3c";
    var promise,response;
    var messages={
            "ZERO_RESULTS":"No results were found",
            "OVER_QUERY_LIMIT":"We are over the query limit.Wait awhile before making a request",
            "REQUEST_DENIED":"Request was denied,probably using a bad or expired API Key",
            "INVALID_REQUEST":"Request was sent without the required address,component or component",
            "UNKNOWN_ERROR": "There was an error somewhere on Google's servers" 
    };
    if(address)
        promise=Q($.ajax({
            type: "GET",
            url: "https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=API_KEY"
        }));
        return promise.then(function(data) {
            if (data.status === "OK") return data;
            else    console.error(messages[data.status]);
            return null;    
        });
}
当我调用函数
makeGeoCodingRequest
request时,我发现我得到的是一个承诺而不是一个值:

 var geo=makeGeoCodingRequest(address);
 console.log(Q.isPromise(geo));//returns true

为什么不在返回值之前执行promise?如何从这个承诺而不是另一个承诺中获得值?

如果希望代码等到异步操作完成后再继续(坏主意-请求完成时页面将冻结),则将
async:false
添加到ajax请求的参数中


不过,我的建议是让
makeGeoCodingRequest
不直接返回任何内容,只需给它一个额外的参数,
requestCallback
,这样它的调用者就可以传入一个函数,当数据可用时将调用该函数。在
承诺内调用该函数,并使用生成的数据。然后
函数。

您将从函数makeGeoCodingRequest返回承诺。我认为这是一件好事,如果将来需要,这可以帮助您链接更多的异步调用。我建议对返回的承诺使用.then(),并按以下方式检查该承诺是否有任何返回值或错误

var geoPromise = makeGeoCodingRequest(address); 
geoPromise.then(
   onSuccess(result){
       // You can use the result that was passed from the function here.. 
   }, 
   onFailure(response){
      // Handle the error returned by the function.
   }
);

如果为了返回数据而依赖于承诺,则必须从函数返回承诺

一旦调用堆栈中的1个函数是异步的,如果要继续线性执行,所有要调用它的函数也必须是异步的。 (异步=返回承诺)

请注意,
if
语句没有大括号,因此,如果条件失败,则只会执行它后面的第一条语句

我在这个例子中修复了它。注意我添加的评论

if(address){
    promise=Q($.ajax({
        type: "GET",
        url: "https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=API_KEY"
    }));
    return promise.then(function(data) {
        // whatever you return here will also become the resolve value of the promise returned by makeGeoCodingRequest
        // If you don't want to validate the data, you can in fact just return the promise variable directly
        // you probably want to return a rejected promise here if status is not what you expected
        if (data.status === "OK") return data;
            else console.error(messages[data.status]);
        return null;    
    });
}
您必须以以下方式调用
makeGeoCodingRequest

makeGeoCodingRequest(address,bounds).then(function(data){
    // this will contain whatever 
    console.log(data);
});
我发现我得到的是承诺而不是价值

是的,因为该操作是异步的,并且返回一个表示未来值的承诺

为什么不在返回值之前执行promise

因为它是异步的
。那么,
将()在返回另一个承诺之前永远不会执行其回调

我如何从这个承诺而不是另一个承诺中获得价值

您正在回调中获取值:

makeGeoCodingRequest(address).then(function(geo) {
    console.log(geo)
    console.log(Q.isPromise(geo)); // false
    // do anything with the value here
})
// if you need to do anything with the result of the callback computation:
// you're getting back another promise for that!

从promise()同步获得它是不可能的。这意味着阻塞执行,这是我们不想要的——让我们保持异步和非阻塞

如果我的回答有问题,也许有人可以提出改进的建议?您提出的同步请求的建议并没有解决OP不理解承诺概念这一事实。除此之外,这是错误的。您需要设置一个
async:false
,以实现同步请求。就像你注意到自己一样,在几乎任何情况下,这都是个坏主意。在函数中引入回调也是一个坏主意,因为显然
makeGeoCodingRequest
应该只返回一个承诺,将两者混合使用是一种反模式,对初学者来说是一种困惑;我把异步值弄错了。这一部分实际上是解释为什么他的代码不能简单地返回一个值。我想我个人并不熟悉这样的意识形态:哪些功能应该继续使用给定的“承诺”对象,哪些应该转换为简单化的功能;所以这对我来说是新的。我没有建议他两者都用。你的答案仍然是建议他两者都用。不,不是。请仔细阅读。第一段以“如果你想让你的代码等待…”开头,也表示这是个坏主意。第二段是另一段。如果我决定使用
promise。然后(…)
返回promise
,然后使用
makeGeoCodingRequest(地址,边界)。然后(…)
,它还会是一样的吗?是的,
makeGeoCodingRequest
返回的承诺将与
承诺中的返回值具有相同的值。然后
处理程序。您可以通过返回类似
Q.reject(新错误(“Http请求失败”+data.status))
谢谢您的回答,一切正常,包括Q.reject。解释得很好。参考“如何从AJAX调用返回响应”以及与此问题相关的其他问题可能会很有趣。您的基本意思是,您想做的任何事情都必须在
然后
方法中完成,使用
数据
作为
参数
回调
中获取我想,就像
回调一样。是的。只不过你得到了回调结果的另一个承诺,这使它们成为可链接的。你还得到了免费抛出统一错误处理的可能性。承诺不给出值,而是使用
将要使用该值的函数传递到承诺中。然后()