1

一周前我问了一个类似的问题,但对我的问题没有真正的答案。那是由于我暴露问题的方式。

我正在写一个 jquery 谷歌地图插件,所以我们可以做这样的事情:

var my_map = $('#map').plugin();
my_map.addMarker( 'Melbourne, Australia' );
my_map.addMarker( 'New York, USA' );
console.log ( my_map.getMarkers() );  // how to return markers array here ?

要添加我的标记,我使用谷歌地理编码,它将地址转换为纬度和经度。一旦我得到响应,我就会将我的标记添加到地图中并将它们存储在一个数组中。

这一切都很好。为了检索我的标记数组,我在插件中完成了这个:

self.getMarkers = function()
{
    self._deferred.done( function()
    {
        // I need to pass this to the outer scope
        console.log( 'Deferred done :' , self.markers ); 
        return self.markers;
    });
 }

如果我self.markers不使用就返回,deferred那么数组是空的,因为响应还没有返回,但是如果我使用,deferred那么我不能将数组传递给外部范围。

此外,我不希望使用插件的开发人员必须这样做:

my_map.done( function( markers ) {
   // code
});

我可以通过返回承诺来做到这一点,但我想通过这样做来获得标记数组my_map.getMarkers()

我希望问题很清楚,如果不是,请向我澄清。如果您需要查看完整代码,请访问此处:http: //jsfiddle.net/Vy4da/

4

2 回答 2

1

根据您的评论,您至少还有 2 个选项。

由于getMarkers()实际上是一个同步调用,它对已经发生的事情进行数据处理,因此您只需要处理addMarker()异步的情况。在这里,您需要做的就是确保您已完成添加标记。例如:

// For this to work, you need to put return statements at the start of addMarker and
// placeMarker so that they return the promises they are making

$.when(my_map.addMarker("Melbourne"), my_map.addMarker("New York, USA"))
.then(function()
{
   // a synchronous my_map.getMarkers() is safe to use here
   // just return self._Markers.markers;
});

如您所见,唯一的困难是并行化addMarker事件并且仅getMarkers在它们全部完成时使用。我建议将这部分作为插件的一部分来简化开发人员的工作。

self.addMarkers = function( /*...*/ ) // accept array of location or comma separated list
{
    var args = [].concat(Array.prototype.slice.call(arguments));
    return $.when.apply(null, args.map(self.addMarker, self));
}

用法:

my_map.addMarkers('Melbourne, Australia', 'New York, USA')
.then(function()
{
   console.log(my_map.getMarkers()); // works if synchronous
   console.log(my_map._Markers.markers); // also works
});

在行动中看到它:http: //jsfiddle.net/Vy4da/1/

您的第二个选项是在向您发出请求后返回与原始请求对象分开的评估对象。这是 AJAX 在 Jquery 中使用的模式。您将选项传递给,然后将其与 链接起来,其中是一个评估对象,可让您评估结果,并且可能是您最感兴趣的部分(jqXHR.responseText)。要在您的情况下使用相同的模式,根本不会出现,而是附加到由地图请求函数解析的构造对象。这种方法可以防止开发人员在它可用之前错误地使用它,因为它根本没有被定义,除非通过 Promise 解决。my_map$.ajaxdone(function(data,status,jqXHR){...})jqXHRdatagetMarkers()my_mapgetMarkers()


原始答案 (基于 getMarkers 是异步的误解)

如果my_map.getMarkers()是任何类型的异步请求,则不能将其视为同步变量赋值。

所以:var a = my_map.getMarkers()永远不会有异步调用的结果。

如果您改为返回一个承诺,则您授予调用者决定如何将此调用与其他异步调用并行化的选项。

my_map.getMarkers().done( function( markers ) { });是更优雅的解决方案之一,因为它允许他们以显示类似同步的控制逻辑的风格编写代码,同时仍然是异步调用。它还允许他们以他们喜欢的任何方式处理错误情况。

一开始我知道这很烦人,但这只是异步编程的现实。

于 2013-02-06T06:06:04.543 回答
1

这不是异步代码的工作方式。当您调用它时,my_map.getMarkers()如果它进行异步调用,您绝对不能保证它何时完成并且可以在调用“之后”访问代码。您必须以某种方式公开这是一个异步调用的事实。

在我看来,暴露最少的方式是允许用户提供一个回调函数,该函数使用以下方式返回的数组:

my_map.getMarkers(function (array) {
    //do stuff with returned array here
});

您可以将该回调函数绑定到.done. 不过,我认为通过返回承诺本身,您将获得更大的灵活性。我想你可以两者都做。

于 2013-02-06T03:15:42.550 回答