我有一些GPX文件,这些文件包含要在node.js脚本中重播的路由。这是为了支持测试地理应用程序,因此我想以与捕获路线时相同的时差重播航路点。因此,例如,如果我有一个像这样的文件:

<?xml version="1.0" encoding="UTF-8"?>
<gpx
  version="1.1"
  creator="Runkeeper - http://www.runkeeper.com"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.topografix.com/GPX/1/1"
  xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
  xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1">
<trk>
  <name><![CDATA[Running 7/9/13 5:12 pm]]></name>
  <time>2013-07-09T22:12:45Z</time>
<trkseg>
<trkpt lat="46.414311000" lon="-94.356703000"><ele>386.7</ele><time>2013-07-09T22:12:45Z</time></trkpt>
<trkpt lat="46.414328000" lon="-94.356708000"><ele>386.0</ele><time>2013-07-09T22:12:46Z</time></trkpt>
<trkpt lat="46.414404000" lon="-94.356637000"><ele>385.6</ele><time>2013-07-09T22:12:49Z</time></trkpt>
<trkpt lat="46.414486000" lon="-94.356562000"><ele>385.4</ele><time>2013-07-09T22:12:52Z</time></trkpt>
...


我希望脚本处理第一个点,等待1秒,然后处理第二个,等待3秒再处理第三个点,然后再等待3秒再处理最后一个点……依此类推。可能根本没关系,但是我要获取这些数据并更新Firebase数据库,因此我需要对每个数据点进行其他“异步”处理。

我可以毫无问题地将数据放入数组,所以我尝试使用带有一些setTimeout调用的简单foreach循环,但是我同时触发了许多更新,每个更新都被延迟了一段时间。然后我尝试使用像这样的可观察对象:

    // waypoints is an array of the ... waypoints
    //
    Observable.from(waypoints)
        .zip(Observable.timer(0, 1000), x => x)
        .subscribe(async waypoint => {
            // await'ing firebase stuff
        });


这让我用很少的代码延迟每个数据点,但仅延迟一个固定的数量,而不使用每个航路点之间的间隔。我试图用处理数据点时可以加减的变量替换1000,但仍无法使它正常工作。

是否有另一种方法使用可观察对象(或其他方法)来获得此行为?

我看到js确实不是要同步工作,但是我在C#中花了很多时间,所以我不反对只使用它,而是希望学习新的知识:)

最佳答案

您可以使用startWithpairwise运算符发出先前和当前的航路点,然后可以将concatMap运算符与可观察到的延迟适当的量一起使用:



const waypoints = Rx.Observable.from([{
  lat: 46.414311000,
  lon: -94.356703000,
  time: Date.parse("2013-07-09T22:12:45Z")
}, {
  lat: 46.414328000,
  lon: -94.356708000,
  time: Date.parse("2013-07-09T22:12:46Z")
}, {
  lat: 46.414404000,
  lon: -94.356637000,
  time: Date.parse("2013-07-09T22:12:49Z")
}, {
  lat: 46.414486000,
  lon: -94.356562000,
  time: Date.parse("2013-07-09T22:12:52Z")
}]);

const replay = waypoints
  .startWith(null)
  .pairwise()
  .concatMap(([previous, current]) => previous ?
    Rx.Observable.of(current).delay(current.time - previous.time) :
    Rx.Observable.of(current)
  )
  .subscribe(waypoint => console.log(waypoint));

.as-console-wrapper { max-height: 100% !important; top: 0; }

<script src="https://unpkg.com/rxjs@5/bundles/Rx.min.js"></script>

09-18 12:20