【问题标题】:nodejs write file frequentlynodejs频繁写入文件
【发布时间】:2016-06-05 04:39:56
【问题描述】:

我有一个监听器来监听内容的变化,一旦内容被修改,它就会发出处理函数:

$('#editor').on('onchange', () => changeHandler('...','...'));

function changeHandler(filePath, content){
    var ws = fs.createWriteStream(filePath, 'utf8');
    ws.write(content);
}

我的问题是'onchange'发生的太频繁了,所以'write file'处理的太频繁了,期间可能会丢失数据。 有人可以给点建议吗?

更新 现在我根据以下答案更改了代码:

this.buffer = null; //used to cache

// once content changed, maybe too often
changeHandler() {        
    if (this.editor.curOp && this.editor.curOp.command.name) {
        var id = $('.nav-items li.active .lk-hosts').attr('data-hosts-id');
        var content = this.editor.getValue();
        // cache data, not immediately write to file
        this.buffer = {id: id, content: content};
    }        
}

setInterval(()=> {
        // means there's data in cache
        if (this.buffer !== null) {
            let id = this.buffer.id;
            let content = this.buffer.content;
            // reset cache to null
            this.buffer = null;
            // write file
            this.writeContent(id, content, (err)=> {
            })
        }
    }, 800);

感谢所有答案!

【问题讨论】:

  • 您可以限制事件,使其最多每 X 秒发生一次。
  • 为什么不让'onchange'控制一个计时器,当它倒计时到0时,保存内容。快速打字只会将计时器重置为满,并且您只会在打字停止时间足够长以使计时器达到 0 时保存。
  • 只是好奇,你如何在同一段代码中拥有内容更改监听器和fs.createWriteStream()?还是其中一个在浏览器中,另一个在服务器中?
  • @jfriend00 可能是这样,但我有这个的浏览器仿真,请检查我的答案并分享想法
  • @MedetTleukabiluly - 我对你的猜测不感兴趣 - 我希望 OP 告诉我们真正的环境和真正的问题是什么,以便我们提供最佳答案。到目前为止,OP 没有对问题做出回应。

标签: javascript node.js asynchronous


【解决方案1】:

下面的这个示例展示了如何进行去抖动事件处理,虽然它不是 node.js 代码,但在概念上是相同的。

// eventEmitter variable to use
var emitter = new EventEmitter();

// dom element change event
$('#editor').on('input', function(event) {
  emitter.emit('changeEvent', event.target.value);
});

// event listener, which debounces change event of input
emitter.on('changeEvent', debounce(function(data) {
  writeFile('li', data);
}, 1000)); // <== debounce for 1second


// sample emitter, for demo
// we don't have access to nodejs EventEmitter class in Stackoverflow 
// don't use in production
function EventEmitter() {
  var callbacks = [];
  return {
    on: function(eventName, fn) {
      callbacks.push({
        eventName: eventName,
        callback: fn
      })
    },
    emit: function(eventName, payload) {
      var fn = callbacks.find(function(item) {
        return item.eventName === eventName;
      });
      if (fn) {
        fn.callback(payload);
      }
    }
  }
}

// simple logger for demo purpose
// emulates write file 
function writeFile(name, content) {
  var $elem = $(document.createElement(name));
  $elem.text(content);
  $('#logger').append($elem);
}

// throttle function - reduces fn call with timeout
// credits: https://remysharp.com/2010/07/21/throttling-function-calls
function debounce(fn, delay) {
  var timer = null;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      fn.apply(context, args);
    }, delay);
  };
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="editor" placeholder="Enter text, this will emit change event"></textarea>

<p>
  Notice the 1sec throttle (write something, pause for 1sec, write again)
</p>

<ul id="logger"></ul>

debounce 函数也可以用于 textarea 更改事件

// debounce emitting
$('#editor').on('input', debounce(function(event) {
  emitter.emit('changeEvent', event.target.value);
}, 1000));

// write file when received event without debounce
emitter.on('changeEvent', function(data){
  logElement('li', data);
});

【讨论】:

  • 我会将其更改为 filter 而不是 find 以便在同一事件上向多个侦听器发出声音
  • @DanielKrom // sample emitter, for demo 这不是一个真正的发射器,只是一个样本
  • 对,+1 很好的解释
【解决方案2】:

为什么不简单地构建一个缓冲区来收集写入的文本,然后仅在您有一定数量的写入时才写入文件:

$('#editor').on('onchange', () => changeHandler('...','...'));

var writeBuffer = ''; // can also make this an array
var writeBufferSize = 0;
var filePath = 'path_to_file';
var ws = fs.createWriteStream(filePath, 'utf8');

function changeHandler(content){
    if (writeBufferSize == SOME_THRESHOLD) {
        ws.write(writeBuffer);
        writeBuffer = '';
        writeBufferSize = 0;
    } else {
        writeBuffer += content + '\n';
        writeBufferSize++;
    }
}

如果您选择的写入缓冲区阈值太大,您可能希望将写入委托给某个工作线程以并行完成,在这种情况下,您可以创建另一个临时写入缓冲区以在原始写入缓冲区时填充写好了,然后切换两者。

【讨论】:

    【解决方案3】:

    Underscore 库有 _.throttle()_.debounce() 函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-05
      • 2019-02-22
      • 2012-11-13
      • 2018-12-27
      • 1970-01-01
      相关资源
      最近更新 更多