【问题标题】:Am I using setTimeout in an inefficient manner?我是否以低效的方式使用 setTimeout?
【发布时间】:2019-06-13 07:31:44
【问题描述】:

我有一个 Angular 应用程序,我想实现一个“Time Ago”功能。如果我提出一些疯狂的“问题”,这会是个坏主意吗?

如果你能想象一个 Facebook 帖子说“大约一分钟前发布...”,这就是我要拍摄的内容。

假设用户从未刷新页面,问题被附加到来自signlar hub的角度mdoel

export interface IQuestion {
  timeAgo: string;
}

export class Question implements IQuestion {
  public timeAgo: string;
  constructor(question: IQuestion) {
    this.timeAgoTicker();
  }
  timeAgoTicker(): void {
    this.timeAgo = 'just now';
    setTimeout( () => this.timeAgo = 'about a minute ago', 10000);
    setTimeout( () => this.timeAgo = 'a couple of minutes ago', 20000);
    setTimeout( () => this.timeAgo = '5 minutes ago', 50000);
    // etc...
  }
}

【问题讨论】:

  • 嗯,我希望有一个超时来查看所有问题并使用 switch 语句在页面上更新它们。这会增加页面的负载(虽然不是什么大问题)
  • 我应该提到,问题正在通过 SignalR 实时传递。假设“何时启动计时器”的管理是准确的。
  • 这有点远离将我们的模型与我们的演示文稿分开。有道理?多语言等呢?我认为这个想法很酷。但我仍然会集中刷新查看模型集合的表示层。
  • 如果你看一下 StackExchange 是如何做到这一点的,他们确实会启动一个 60000 毫秒的间隔来查找所有 $('span.relativetime, span.relativetime-clean'),然后根据 currentTime 更新他们的 textContent。 (在full.js
  • 如果你整理 full.js,你会发现有一个工厂 StackExchange.realtime 可以做到这一点。搜索relativetime 找到函数L(将来可能会更改),然后搜索在同一范围内调用此函数的位置(它在当前版本的函数r 中),然后就可以了会看到它是在一个函数内部调用的,它本身每 60000 毫秒调用一次。

标签: javascript angular settimeout


【解决方案1】:

我不知道多次调用 setTimeout 对性能有何影响,但我宁愿将timeAgo 设置为日期对象,然后在更新 UI 时检查now 与该日期对象之间的差异:

export interface IQuestion {
  createdAt: Date;
}

export class Question implements IQuestion {
  public createdAt: Date;
  constructor(question: IQuestion) {
    this.createdAt = new Date();
  }

  getAge(): String {
    return (new Date() - this.createdAt).toSomeStringAccordingToAge()
  }
}

我不知道语法是否正确,因为我不使用 Typescript。例如,正如下面提到的 cmets 之一所说,最好使用访问器 (getter)。

【讨论】:

  • 然后在其他地方你可以有一个 setTimeout 方法,它会根据结果定期更新 UI。或者如果它是单向状态传播,那么 getAge() 方法应该更新它
  • 我猜想在组件上实现一个功能来呈现计算时间前的答案将是另一种选择。我想我关心的是数量。如果只是几个问题,那没关系。但如果我最终有 100 万个问题,那显然不会成功。在那个离谱的例子中,您是宁愿运行 setTimeout 来重新评估列表,还是让每条记录自己更新为 setTimeout
  • 我不知道如果运行一百万次,即使 const x = 'hi' 会做什么。而是根据您当前的最佳知识使其工作,然后在出现性能瓶颈时解决它们。从长远来看,这将节省您的时间。
  • 否则您会发现您的“优化”解决方案需要花费时间才能真正优化 - 所以无论如何您都必须更改它们,它们往往会使代码更复杂
  • 我喜欢这个,但有一个建议。使用 getter 代替方法 get age(): String { return ... }
【解决方案2】:

好的,newQuestion 和第一个 setTimeout 只是样板代码,用于测试工作。请无视。第二个 setInteval 是我们查看data 属性的地方。此属性符合 HTML 标准。并可通过[HTMLElement].dataset 访问。我们根据当前测试我们的发布时间。在单一方法中。

const newQuestion = () => {
  let target = document.querySelector('.questions');
  let question = document.createElement('div');
  question.className = 'question';
  question.setAttribute('data-question-date', Date.now());
  question.innerHTML = '<span>Test Question - <span><span class="age">Just Now</span>';
  target.appendChild(question);
  
};

document.addEventListener('DOMContentLoaded', () => {
  setInterval(() => {
    newQuestion();
  }, 5000); 
  
  setInterval(() => {
    let questions = document.querySelectorAll('.question');
    questions.forEach(q => {
      let dateofQ = q.dataset.questionDate;
      let age = Math.floor((Date.now() - dateofQ)/1000);
      console.log(`age: ${age}`); 
      let ageElement = q.querySelector('.age');
      //do just 20 secs, so we don't have to wait.
      if(age < 20) {
        ageElement.innerHTML = 'Just now';
      } else if (age < 300) {
        ageElement.innerHTML = 'Less than 5 minutes ago.';
      } else {
        ageElement.innerHTML = 'More than 5 minutes ago.';
      }
    });
    
  }, 1000);
});
<div class="questions">


</div>

【讨论】:

  • 我没有对此投票,但仅代码的答案经常被否决。如果您可以添加一些解释,它会更有帮助。
  • 问题不是“怎么做”。这是“这是最有效的方法吗”。您的回答不仅违反了 Angular 框架,而且还反刍了如何做已经以 vanilla js 方式完成的事情——这没有被问到。
  • 但你问它是否“高效”。香草只是用来搭建演示。
猜你喜欢
  • 2010-09-13
  • 2016-12-22
  • 2015-08-05
  • 2011-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多