我有一个Web地图应用程序,它有一个按钮,当点击它时会调用一个返回大型JSON的Web服务。 JSON字符串的一部分表示我需要将地图缩放到的空间范围。 JSON的主要内容("结果"以下部分)需要几秒钟的时间来处理,并与" extentToZoomTo"无关。部分。我使用的映射API有一个setExtent方法,它返回一个 DOJO Deferred 对象。 setExtent方法在服务器上生成图像 ,可能需要几秒钟才能完成。我想要做的是在获得JSON后立即调用setExtent方法,并且当服务器忙于处理时,浏览器上的客户端javaScript代码可以处理"结果" JSON的一部分同时出现。我怎么能做到这一点?我发现如果我在开始处理"结果之前简单地调用setExtent"部分,它实际上并没有将该请求发送到服务器,直到结束部分已经完全处理完之后。我可以通过检查开发人员工具中的“网络”选项卡来验证该行为(当我获得JSON和调用setExtent方法之间存在几秒钟的差距)。我猜这与setExtent延期这一事实有关。我怎么才能马上开火呢?
{
"extentToZoomTo": {
"xmin": 1234,
"ymin": 4567,
"xmax": 2345,
"ymax": 5678
},
"results": {
//A very large amount of data here that takes several seconds to process
}
}
----编辑--- 我可以以某种方式同时运行两个Deferred&?s?下面的伪类型代码
mainMethod(){
let bigJSONString: string = "big json string with results and extent info retrieved from web service call";
//get extent info from bigJSONString...for now, just mock the values
let xmin = 123; let ymin = 234; let xmax = 345; let ymax = 789;
let jsonExtent: esri.geometry.Extent = new esri.geometry.Extent(xmin, ymin, xmax, ymax, spatialRef);
//I want to call setExtent and handResults in parallel...how do I do that?
let setExtentDeferred: dojo.Deferred = myMap.setExtent(jsonExtent);
let handleResultsDeferred: dojo.Deferred = this.handleResultsDeferred(bigJSONString);
dojo.Deferred.RUN_IN_PARALLEL(setExtentDeferred, handleResultsDeferred);
}
handleResultsDeferred(jsonString: string): dojo.Deferred {
//This code does the real work...should I return a dojo.Deferred from here?
return new dojo.Deferred();
}
答案 0 :(得分:0)
Deferred对象类似于标准的JavaScript Promise或Java Future。它只是在后台进程完成时通知代码的一种方式。这与单词" defer"的含义不同。用于其他一些语言,例如Go,它表示操作被推迟到以后。
然而...... setExtent
方法可能仍会推迟到handleResults代码之后。如果发出JSON请求的setExtent
中的代码以setTimeout
或其他异步方式运行,则会延迟到JavaScript事件循环的下一个滴答,这将在另一个之后结果处理代码(假设它是同步的)。
setExtent
代码实际上有两个级别的异步。首先,功能代码是异步的(这就是为什么你没有看到发出请求直到你预期之后)。第二个是请求本身。它看起来像是:
let jsonExtent = expo.Extent
+---let setExtentDeferred = myMap.setExtent(jsonExtent);
| handleResults()
| // any other sync code runs
|
| -- current event loop cycle ends --
|
+-> // setExtent code actually runs here and starts a request
// other sync code runs
-- time passes --
// request completes
同步操作按顺序运行,任何异步操作都会延迟一段时间。
要使某些内容并行运行,您需要在发出请求后,但在它完成之前启动处理代码。请注意,请求是其中唯一可以与其他任何内容并行运行的部分。除了像服务工作者这样的新功能之外,JavaScript代码是单线程的,只有少数操作(如请求)可以在JavaScript代码运行的同时实际执行操作。
要在启动JSON请求后启动处理代码,您只需将其推迟到JS事件循环的下一个滴答。如果您确实希望在setExtent
请求和处理完成时收到通知,则可以使用DeferredList。请注意,DeferredList不以任何特殊方式运行延迟(Deferred只是一个通知程序,而不是要运行的东西),它只是一种让你知道它们何时完成的方式。
mainMethod(){
let bigJSONString: string = "big json string";
let xmin = 123; let ymin = 234; let xmax = 345; let ymax = 789;
let jsonExtent = new esri.geometry.Extent(...);
let setExtentDeferred = myMap.setExtent(jsonExtent);
let handleResultsDeferred = this.handleResultsDeferred(bigJSONString);
let dfd = dojo.DeferredList([setExtentDeferred, handleResultsDeferred]);
// dfd will resolve when both setExtentDeferred and handleResultsDeferred
// have resolved.
}
handleResultsDeferred(jsonString: string): dojo.Deferred {
let dfd = new dojo.Deferred();
// Run code in a setTimeout with no timeout -- the goal isn't to delay it
// for any period of time, but just to defer it until the next tick of the
// JS event loop.
setTimeout(function () {
// do work here
dfd.resolve();
});
return dfd;
}
这会给你类似的东西:
let jsonExtent = expo.Extent
+-----let setExtentDeferred = myMap.setExtent(jsonExtent);
| +---let handleResultsDeferred = handleResults()
| | // any other sync code runs
| |
| | -- current event loop cycle ends --
| |
+-|-> // setExtent code actually runs, starting a request
+-> // handle results code runs
-- time passes --
// request completes
// DeferredList resolves