Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何强制立即执行延迟的方法?_Javascript_Performance_Asynchronous_Dojo_Deferred - Fatal编程技术网

Javascript 如何强制立即执行延迟的方法?

Javascript 如何强制立即执行延迟的方法?,javascript,performance,asynchronous,dojo,deferred,Javascript,Performance,Asynchronous,Dojo,Deferred,我有一个web映射应用程序,它有一个按钮,单击该按钮时调用一个返回一个大JSON的web服务。JSON字符串的一部分表示我需要将地图缩放到的空间范围。JSON的主要部分(下面的“结果”部分)需要几秒钟的处理时间,与“extentToZoomTo”部分无关。我使用的映射API有一个setExtent方法,它返回一个DOJO-Deferred对象。setExtent方法在服务器上生成一个映像,可能需要几秒钟才能完成。我想做的是在获得JSON后立即调用setExtent方法,当服务器忙于处理该方法时,

我有一个web映射应用程序,它有一个按钮,单击该按钮时调用一个返回一个大JSON的web服务。JSON字符串的一部分表示我需要将地图缩放到的空间范围。JSON的主要部分(下面的“结果”部分)需要几秒钟的处理时间,与“extentToZoomTo”部分无关。我使用的映射API有一个setExtent方法,它返回一个DOJO-Deferred对象。setExtent方法在服务器上生成一个映像,可能需要几秒钟才能完成。我想做的是在获得JSON后立即调用setExtent方法,当服务器忙于处理该方法时,浏览器上的客户端javaScript代码可以同时处理JSON的“结果”部分。我怎样才能做到这一点??我发现,如果我在开始处理“results”部分之前简单地调用setExtent,它实际上不会将该请求发送到服务器,直到results部分完全处理完毕。我可以通过检查开发人员工具中的Network选项卡来验证这种行为(在获取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
  }
}
----编辑--- 我可以并行运行两个延迟的吗?下面是伪类型脚本代码

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();
}

延迟对象类似于标准JavaScript承诺或Java未来。这只是在后台进程完成时通知代码的一种方式。这与其他一些语言(如Go)中使用“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
      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
同步操作按顺序运行,任何异步操作都将延迟到稍后的时间

为了使某些事情并行运行,您需要在发出请求之后但在请求完成之前启动处理代码。请注意,请求是其中唯一可以与其他任何内容并行运行的部分。除了像服务工作者这样的新特性之外,JavaScript代码是单线程的,并且只有少数操作(比如请求)可以在JavaScript代码运行的同时执行

要使处理代码在JSON请求启动后启动,只需将其推迟到JS事件循环的下一个周期。如果您确实希望在
setExtent
请求和处理完成时收到通知,则可以使用延迟列表。请注意,延迟列表并没有以任何特殊方式运行延迟(延迟只是一个通知程序,而不是要运行的东西),它只是一种让您知道它们何时都已完成的方式

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);
|   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
      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

您可以使用2个延迟并并行运行它们。在这两个响应返回后,您可以使用dojo/deferred/all做一些事情。如果您需要更多帮助,请发布一些代码。Philipe-谢谢您回复我。我不太确定如何执行您的建议。您需要将后端拆分为两个独立的端点。一个返回extentToZoomTo,另一个返回结果。你对后端有控制权吗?我对myMap.setExtent没有控制权。我确实可以控制HandlersSultsDerred。myMap.setExtent将导致网络调用,而HandlerResults是所有客户端JavaScript。看起来您使用的是AMD之前的dojo。检查谢谢您的回复-我尝试了您的建议,但从setExtent生成的网络调用直到处理结果后才开始。也许我做错了什么。在setExtentDeferred中,我假设还应该传回一个dojo.deferred,对吗?我应该在setExtentDeferred和HandlerResultsDeferred中调用.resolve()?由于map.setExtent本身返回一个延迟的,也许我甚至不需要setextdeferred方法。您在哪里调用
setextdeferred
方法?正如您所说,如果
setExtent
返回一个deferred,则在调用它时不需要执行任何其他操作。我需要将外部上下文传递到setTimeout()中,第二个timeout参数为null。没关系,对吧?基本上就是这样:```让dfd=new dojo.DeferredList([map.setExtent(extent),this.setResultsDeferred()]),然后(()=>{//done});setResultsDeferred():dojo.Deferred{let dfd=new dojo.Deferred();let context=this;setTimeout(函数(){//一大堆工作…let x=context.getSomething();dfd.resolve();},null,collection,context);return dfd;}````是的,实际上不需要超时,所以省略它或将它设置为0是可以的。出于好奇,您将上下文参数作为参数传递给setTimeout有什么原因吗?在setTimeout中,setResults需要执行的工作需要访问以前执行的一些数据。至少在TypeScript中,我无法使用this.myData访问该数据,因为“this”指的是其他内容。因此,通过传递它,我可以绕过它。