3

我正在尝试通过 WebRTC 传输文件,并且我正在努力找出写入数据的良好模式。由于文件块将以未知的速度进入,我需要能够编写每个块可用时;这意味着两件事:

  1. 如果数据进来太快,那么我们需要在当前写入任务完成后将每个块排队等待稍后写入
  2. 如果数据进来太慢,那么我们需要等待一个块变得可用

理想情况下,我想避免不得不依赖setTimeout()等待大块到达。到目前为止我所拥有的很接近,但并不完全是我想要的:

// container to hold chunks as they come in
var chunkCollection = {};

// callback function for RTCDataChannel messages
function onData(data) {

  chunkCollection[data.chunkIndex] = data.chunk;
  writeToFile(data.chunkIndex);
}

function writeToFile(chunkIndexToWrite) {

  // if we have the next chunk, write it to the file
  if (chunkCollection[chunkIndexToWrite]) {
    var chunk = chunkCollection[chunkIndexToWrite];
    delete chunkCollection[chunkIndexToWrite];
    fileWriter.seek(chunk.offset);
    fileWriter.write(chunk.blob);
  }
  else {
    // we don't have the next chunk, so we have to wait
    setTimeout(function() {
      writeToFile(chunkIndexToWrite);
    }, 100);
  }
}

这样做的问题是,如果块进入得太快,fileWriter将无法准备好写入下一个块并且会抛出异常。但是,如果块进入太慢,设置正确的超时将非常棘手。

似乎事件驱动的方法在这里效果最好。一个事件是来自 的数据消息RTCDataChannel。另一个事件是fileWriter已经完成写入,并准备写入下一个块。但我遇到的问题是如何正确地等待一大块进来......

如果浏览器不忙于写入文件,而只是等待块进入,则浏览器应该在块可用时立即开始写入块。setTimeout但是如果没有丑陋的循环,我无法弄清楚如何做到这一点;我不知道如何发布一个表明我们不再需要等待并且可以继续写作的事件。

这样做的好模式是什么?

4

1 回答 1

1

有一种方法可以在没有超时的情况下做到这一点,尽管它使用标志来指示编写器可用,但它仍然应该比超时循环更好。

我将创建队列,当数据块到达时将在其中存储数据块,并使用异步 fileWriter(一个在完成写入文件时执行回调的队列)。

像那样:


var readyToWrite = true;
var chunks = [];

var onData = function(data) {
    chunks.push(data);
    if (readyToWrite) {
         writeChunksToFile(chunks);
    }
};

var writeChunksToFile = function() {
    if (chunks) {
        readyToWrite = false;
        fileWriter.write(chunks.shift(), function() {
            writeChunksToFile(chunks);
        });
    } else {
        readyToWrite = true;
    }
};

这样,writer一直在写入,直到变为空,然后它通知数据接收器(使用标志)它可用,因此数据接收器(onData)知道它必须在接收到下一个块时再次调用它。如果数据接收器获取数据并且写入器仍在写入文件,那么它不会调用它,它只会将块推送到我们的队列数组,写入器在完成写入后会获取该块,因为它是递归调用的。

这是我们可以使用该方法编写的最简单的代码,但是您可以使用ObserverPattern使其“更 OOP”或使用Monad使其“更具功能性” 。

于 2015-05-27T10:46:08.867 回答