react-native-fs 在其本机实现中完成所有工作,并通过 react-native 桥公开一个异步 api。因此,在通过 react-native-js 下载文件时,您的 js 线程大部分时间都处于空闲状态,您的 js 是在前台运行还是在后台运行都无关紧要。
实际问题
您的实现的实际问题是downloadFile
会触发下载并立即返回 Promise。因此,您的 for 循环将几乎立即运行所有 15k 次迭代,在您的应用程序的本机部分开始 15k 次并发下载。这可能足以减慢任何设备的速度,以至于整个应用程序被阻止。
解决方案
如果你需要下载很多文件,你应该实现某种队列和流水线来限制并发下载的数量。(即使设备可以毫无问题地处理 15k 并发下载,下载也会受到可用带宽的限制。拥有约 3 次并发下载可能足以一直使用最大带宽。)
一个可能的流水线解决方案可能如下所示:
(以下代码未运行或测试)
/**
*
* @param {item} The item to download
* @param {item.urlPath} The url to download the item from
* @param {item.path} The local path to download the item to
* @returns the Promise returned by react-native-fs downloadFile
*/
const downloadItem = ({ urlPath, path }) => {
const options = {
fromUrl: urlPath,
toFile: path
}
return downloadFile(options);
}
/**
*
* @param {Array} Array of the items to download
* @param {integer} maximum allowed concurrent downloads
* @returns {Promise} which resolves when all downloads are done
*/
const downloadPipelined = (items, maxConcurrency = 3) => {
// Clone the items Array because we will mutate the queue
const queue = [...items];
/**
* Calling this function will
* - donwload one item after another until the queue is empty
* - return a promise which resolves if the queue is empty and
* the last download started from this workerFn is finished
*/
const workerFn = async () => {
while (queue.length > 0){
await downloadItem(queue.shift());
}
}
/**
* starts maxConcurrency of these workers concurrently
* and saves the promises returned by them to an array
*/
const workers = Array(maxConcurrency).fill(workerFn());
/**
* will resolve when all worker promises have resolved
* (all downloads are done)
* reject if one rejects
*/
return Promise.all(workers);
}