【问题标题】:How to emit an event after 5 minutes have elapsed for each item (relative to items timestamp)?如何在每个项目(相对于项目时间戳)过去 5 分钟后发出事件?
【发布时间】:2020-05-14 10:11:01
【问题描述】:

我有一堆项目(如下)正在使用服务获取。

我正在使用 json 服务器从本地 db.json 文件中推送和获取项目。

所以每个项目都使用 json-server 推送到本地数据库。

当推送每个项目时,时间戳也会附加到项目上。

应用背后的想法是跟踪项目。因此,假设在推送项目后是否经过 5 分钟(相对于项目的时间戳,例如 items[index_of_some_item].time 而不是相对于组件的创建)。

因此,当当前时间比数组中项目的时间晚 5 分钟时创建项目后,应用程序会为该特定项目发出一个事件(如消息,“项目 [1] 已过去 5 分钟...像这样)。

这样,应用程序将为每个项目发出通知消息(在创建该特定项目后 5 分钟后...有点像警报)

"items": [
    {
      "item": "foo",
      "hint": "bar",
      "time": 1589446462047,
      "id": 1
    },
    {
      "item": "foo1",
      "hint": "bar1",
      "time": 1589446462047,
      "id": 2
    },


...


]

我想要实现的是,我想在一个项目的时间已经过去 5 分钟时发出一个事件(这应该通过与项目的时间戳进行比较来实现)。

我怎样才能用 rxjs 在 Angular 中做到这一点?

注意 我可以用计时器实现类似的效果。

timer(300000).pipe(// do something)

但是这种方法的问题是它在组件初始化时开始计数。

我想要实现的是我想跟踪每个项目的时间戳,这样如果它已经过了 5 分钟,就会触发一个事件......

这是我尝试过的:但它没有用

    of(this.item.time).pipe(tap(time =>
    {

      if (Date.now() === time + 300000)
      {
        console.log('time has passed');
      }
    })
    ).subscribe();

所以当 Date.now() === time + 300000 时,我想达到这样的效果:-

when

Date.now() === time + 300000

// do something

我想触发一个事件。

再次注意

我不想做与创建组件相关的事情。这是因为如果我关闭应用程序并再次继续使用它,setInterval 将再次为每个先前创建的组件启动。这不公平。

但是,如果我们从 json-server db 文件中观察项目的时间戳,它将与项目的时间戳相关。 & 随着时间的流逝,将为每个项目触发新消息。哪种方法是保持跟踪项目的正确方法。

心理图片

为了清楚地了解应用程序,

让我们想象一个 TODO 应用。 所以每个新项目都会被推送到本地的 json-server db.json 文件中。 & 所有这些新增内容也将反映在模板中。 因此,假设我在待办事项应用程序中添加了 10 个项目。 (假设这只需要几秒钟)。

然后我关闭应用程序(浏览器)。

4 分钟后我回来并重新打开该应用程序(在浏览器中)。

现在每个项目都经过 5 分钟后,我将能够在 5 分钟后看到通知。

现在,如果我再次输入另外 7 个项目,那么 5 分钟后,我将能够看到一条消息,这 7 个项目已经过去了 5 分钟,而前 10 个项目已经过去了 10 分钟,就像这样......如果我输入另外 4 项我会在 15 分钟后收到一条消息,前 10 项已过 15 分钟,后 7 项已过 10 分钟,最后 4 项已过 5 分钟。这让 onnnn gogg...

【问题讨论】:

    标签: javascript angular rxjs


    【解决方案1】:

    这是我的推理:

    • 主要来源包括 2 个可观察的:
      • existent$ - 从服务器接收到的数据
      • newItem - 每次创建新项目时都会发出的主题
    • delayWhen 操作员 - 将根据时间发出此项目的通知
    const BACKOFFTIME = 1000 * 60 * 5;
    
    // Assumed that `getItemsFromServer()` returns Item[]
    // `mergeAll` is used to emit each item individually
    const existentItems$ = getItemsFromServer().pipe(mergeAll());
    const newItem = new Subject<Item>();
    
    merge(
      existentItems$,
      newItem.pipe(
        // `addRawItemToDB` returns `Observable<Item>`
        mergeMap(item => addRawItemToDB(item))
      )
    ).pipe(
      delayWhen(item => {
        const { time: setAt } = item;
        const now = Date.now();
        const delta = now - setAt;
    
        const needsToSendNotif = delta < BACKOFFTIME;
        const toWait = needsToSendNotif ? setAt + BACKOFFTIME - now : 0;
    
        return timer(toWait);
      }),
      map(
        item => ({ 
          ...item, 
          minutesShown: Math.floor((Date.now() - item.time) / BACKOFFTIME),
        })
      ),
      filter(item => item.minutesShown >= 5),
    )
    

    【讨论】:

      【解决方案2】:

      您可以在创建每个对象时为其设置间隔。

      setInterval(function (referenceToObject) {
          runYourFunction(referenceToObject);
      }, 1000*60*5);
      

      或者设置不定式循环检查所有对象的时间戳,如果时间戳较大则调用函数。

      伪代码:

      while(true):
        sleep 1 second
        getAllItems.foreach():
          if(differenceOfNowAndTimestamp > 5 minutes):
            runFunction()
            removeElement or changeTimestampOfElement
      

      【讨论】:

      • 我不想做与创建组件相关的事情。这是因为如果我关闭应用程序并继续使用它,setInterval 将再次启动。这不公平。但是,如果我们从 json-server db 文件中观察项目的时间戳,它将与项目的时间戳相关。这是保持跟踪项目的正确方法。
      • 您需要不定式循环或任何进程检查项目的每个固定间隔(例如 1 秒)时间戳。
      猜你喜欢
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 2016-10-26
      • 1970-01-01
      • 2022-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多