downloadjs vs file-saver vs js-file-download
前端文件下载方案的技术选型与对比
downloadjsfile-saverjs-file-download类似的npm包:

前端文件下载方案的技术选型与对比

downloadjs、file-saver 和 js-file-download 都是用于在浏览器端触发文件下载的 JavaScript 库。它们的核心目标一致:解决原生 <a> 标签在处理 Blob 数据、跨域资源或特定 MIME 类型时的兼容性问题,并提供统一的 API 来保存文件到用户本地。

file-saver 是业界最老牌、使用最广泛的方案,它专注于实现 saveAs() 函数,对各种浏览器内核(包括旧版 IE 和移动端 Safari)有着极深的兼容性处理,是许多大型项目的默认选择。

downloadjs 提供了一个更简洁的函数式 API,它不仅支持 Blob,还能直接处理数据 URL (Data URLs) 和字符串,代码风格更加轻量,适合现代浏览器环境下的快速集成。

js-file-download 则是一个极度轻量的替代品,主要依赖创建临时 <a> 标签并模拟点击的方式,去除了复杂的兼容性 shim,适合只需要在现代浏览器中处理 Blob 下载的场景。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
downloadjs02,328-5110 年前MIT
file-saver021,981-2146 年前MIT
js-file-download0920-116 年前MIT

前端文件下载方案深度对比:downloadjs vs file-saver vs js-file-download

在前端开发中,触发文件下载看似简单,实则暗藏玄机。原生的 <a download> 属性在处理二进制流(Blob)、跨域资源或特定 MIME 类型时,往往在不同浏览器中表现不一。为了解决这些兼容性问题,downloadjs、file-saver 和 js-file-download 应运而生。它们都致力于将内存中的数据安全、可靠地保存为用户本地文件,但实现思路和适用场景各有不同。

🚀 核心 API 设计:函数式 vs 独立方法

这三个库最大的区别在于调用方式。理解它们的 API 形态,能帮你快速决定哪个更符合你的代码风格。

file-saver 导出一个名为 saveAs 的全局函数。它的设计非常明确:第一个参数是文件内容(通常是 Blob),第二个参数是文件名。这种命名方式语义清晰,但在模块化项目中需要显式导入。

// file-saver 用法
import { saveAs } from 'file-saver';

const blob = new Blob(["Hello World"], { type: "text/plain;charset=utf-8" });
// 明确调用 saveAs,语义为“保存为...”
saveAs(blob, "hello.txt");

downloadjs 采用单一的默认导出函数,通常命名为 download。它的参数顺序略有不同:先内容,再文件名,最后可选地指定 MIME 类型。这种设计让调用看起来更像是一个普通的工具函数。

// downloadjs 用法
import download from 'downloadjs';

const data = "Hello World";
// 直接调用 download,支持字符串、Blob 或 Data URL
download(data, "hello.txt", "text/plain");

js-file-download 同样导出一个默认函数,但其参数设计更加聚焦于 Blob 场景。它强制要求第一个参数必须是 Blob 对象,这使得它在处理非 Blob 数据时需要你先手动转换。

// js-file-download 用法
import fileDownload from 'js-file-download';

const blob = new Blob(["Hello World"], { type: "text/plain" });
// 必须传入 Blob,第二个参数是文件名
fileDownload(blob, "hello.txt");

🛠️ 数据类型处理:灵活度大比拼

在实际工程中,数据来源千奇百怪:可能是后端返回的 Blob,可能是 Base64 图片,也可能只是一段简单的 JSON 字符串。不同库对这些类型的支持程度决定了你的预处理工作量。

downloadjs 是三者中最灵活的。它内置了类型检测逻辑,可以直接接受字符串、Blob 对象甚至 Data URL。如果你有一段 Base64 编码的图片,可以直接传给它,无需手动转换为 Blob。

// downloadjs: 直接处理 Data URL
const base64Img = "data:image/png;base64,iVBORw0KG...";
download(base64Img, "image.png"); 
// 库内部自动处理转换,开发者省心

file-saver 主要设计用于处理 Blob 对象。虽然你也可以传字符串,但它通常会将其视为文本并自动包装成 Blob。对于复杂的二进制数据或 Data URL,最佳实践是手动创建 Blob 以确保 MIME 类型准确。

// file-saver: 推荐显式创建 Blob
const base64Img = "data:image/png;base64,iVBORw0KG...";
// 需要手动解析或转换,否则可能被视为纯文本
const byteString = atob(base64Img.split(',')[1]);
const mimeString = base64Img.split(',')[0].split(':')[1].split(';')[0];
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); }
const blob = new Blob([ab], { type: mimeString });

saveAs(blob, "image.png");

js-file-download 最为严格,它几乎完全依赖浏览器原生的 Blob URL 机制。如果传入非 Blob 数据,它可能无法按预期工作或需要你在外部转换。这使得它非常适合处理后端直接返回的文件流,但不适合处理原始字符串。

// js-file-download: 严格依赖 Blob
const jsonData = JSON.stringify({ user: "alice" });
// 必须先手动转换为 Blob
const blob = new Blob([jsonData], { type: "application/json" });
fileDownload(blob, "data.json");

🌍 浏览器兼容性:历史包袱 vs 现代轻量

这是选型时最关键的决策点。你的用户还在使用 IE11 吗?还是全员 Chrome/Firefox?

file-saver 是兼容性之王。它内部包含了大量的 Polyfill 逻辑,专门应对 IE10/11 的 msSaveBlob、旧版 Safari 的文件系统限制以及 Android 浏览器的各种怪癖。如果你的项目需要支持 5 年前的设备,它是唯一稳妥的选择。

// file-saver 内部逻辑示意(伪代码)
if (navigator.msSaveBlob) {
    // IE 特有处理
    navigator.msSaveBlob(blob, filename);
} else if (isSafariOldVersion) {
    // 旧版 Safari 特殊处理
    // ... 复杂的兼容性代码
} else {
    // 现代浏览器标准处理
    link.href = URL.createObjectURL(blob);
}

downloadjs 采取了折中方案。它支持大多数现代浏览器和部分旧浏览器,但在极端情况下(如非常老的 IE 版本)可能不如 file-saver 健壮。它的代码量适中,去除了一些极其罕见的兼容性代码,换取了更好的可维护性。

// downloadjs 处理逻辑相对简化
// 优先使用标准 a 标签下载,降级策略较少
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();

js-file-download 完全拥抱现代标准。它假设运行环境支持 URL.createObjectURL 和 <a download> 属性。这意味着它在 IE11 及更低版本中可能无法工作。如果你的团队已经放弃了对旧浏览器的支持,这个库能为你节省宝贵的包体积。

// js-file-download 核心逻辑极其简单
// 仅依赖现代浏览器 API
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url); // 自动清理内存

🧹 资源清理与内存管理

处理大文件下载时,内存泄漏是一个潜在风险。这三个库在处理临时创建的 Object URL 时策略不同。

file-saver 和 js-file-download 都会在下载触发后尝试清理生成的 Object URL,防止内存堆积。file-saver 由于兼容性代码较多,其清理逻辑分散在不同的分支中,但总体是可靠的。

// file-saver 会在超时或点击后清理
setTimeout(function() {
    URL.revokeObjectURL(url);
}, 60000); // 60 秒后清理

downloadjs 同样具备清理机制,但它的实现更加直接。对于大多数常规文件下载,这三者在内存管理上没有显著差异,除非你在极短时间内触发成千上万次下载。

// downloadjs 同样会在操作完成后释放 URL
// 内部实现确保了 revokeObjectURL 的调用

📊 总结与选型建议

特性file-saverdownloadjsjs-file-download
核心函数saveAs(blob, name)download(data, name, type)fileDownload(blob, name)
数据支持主要 Blob (可转字符串)Blob, 字符串, Data URL仅 Blob
兼容性极强 (含 IE11, 旧 Safari)中等 (主流浏览器)弱 (仅现代浏览器)
包体积较大 (含 Polyfill)中等极小
维护状态稳定,长期维护活跃稳定

💡 最终建议

选择 file-saver 如果: 你正在维护一个面向公众的大型应用,用户设备五花八门,甚至可能包括几年前的旧电脑或安卓机。你需要“一次编写,到处运行”的确定性,不愿意因为浏览器差异去处理 Bug。它是企业级开发的保险单。

选择 downloadjs 如果: 你的项目主要面向现代浏览器,但偶尔需要处理一些简单的字符串或 Base64 数据,不想写额外的 Blob 转换代码。你喜欢简洁的函数式 API,希望代码读起来更像自然语言。它是全栈开发者和快速原型开发的首选。

选择 js-file-download 如果: 你明确知道你的用户群体只使用最新的 Chrome、Edge 或 Firefox(例如内部后台管理系统、SaaS 工具)。你对包体积非常敏感,希望依赖库越小越好。它是现代前端工程化的轻量级利器。

无论选择哪个,都要记住:在处理大文件时,始终关注浏览器的内存表现,并在下载完成后确保临时 URL 被正确释放。

如何选择: downloadjs vs file-saver vs js-file-download

  • downloadjs:

    如果你的项目主要面向现代浏览器,且希望 API 调用尽可能简洁(例如直接传入字符串或 Data URL),downloadjs 是极佳的选择。它的函数签名直观,无需实例化,适合在工具函数或小型项目中快速实现下载功能,但在处理极端老旧浏览器时可能不如 file-saver 稳健。

  • file-saver:

    如果你需要构建企业级应用,必须兼容旧版 IE、旧版 Android 或处理复杂的 Blob 类型,file-saver 是首选。它是社区事实上的标准,经过了无数生产环境的验证,拥有最完善的兼容性兜底方案(如使用 FileSystem API 或 IE 特有的 blob 保存机制),适合对稳定性要求极高的场景。

  • js-file-download:

    如果你追求极致的轻量,且明确知道目标用户群体仅使用现代浏览器(Chrome, Firefox, Edge, Safari 新版),js-file-download 提供了最直接的解决方案。它没有多余的兼容性包袱,代码体积极小,适合对包体积敏感且不需要支持旧设备的项目。

downloadjs的README

download

========

Summary


The download() function is used to trigger a file download from JavaScript.

It specifies the contents and name of a new file placed in the browser's download directory. The input can be a URL, String, Blob, or Typed Array of data, or via a dataURL representing the file's data as base64 or url-encoded string. No matter the input format, download() saves a file using the specified file name and mime information in the same manner as a server using a Content-Disposition HTTP header.

Getting and Using


Via NPM/Bower

npm install downloadjs
bower install downloadjs

require("downloadjs")(data, strFileName, strMimeType);

Simple global download function via <script> include

download(data, strFileName, strMimeType);

Included via AMD

require(['path/to/file'], function(download) {
    download(data, strFileName, strMimeType);
});

Parameters


  • data - The Blob, File, String, or dataURL containing the soon-to-be File's contents.
  • strFileName - The name of the file to be created. Note that older browsers (like FF3.5, Ch5) don't honor the file name you provide, instead they automatically name the downloaded file.
  • strMimeType - The MIME content-type of the file to download. While optional, it helps the browser present friendlier information about the download to the user, encouraging them to accept the download.

Example Usage


Plain Text

text string - live demo

download("hello world", "dlText.txt", "text/plain");

text dataURL - live demo

download("data:text/plain,hello%20world", "dlDataUrlText.txt", "text/plain");

text blob - live demo

download(new Blob(["hello world"]), "dlTextBlob.txt", "text/plain");

text url - live demo

download("/robots.txt");

text UInt8 Array - live demo

var str= "hello world",	arr= new Uint8Array(str.length);
str.split("").forEach(function(a,b){
  arr[b]=a.charCodeAt();
});

download( arr, "textUInt8Array.txt", "text/plain" );

HTML

html string - live demo

download(document.documentElement.outerHTML, "dlHTML.html", "text/html");

html Blob - live demo

download(new Blob(["hello world".bold()]), "dlHtmlBlob.html", "text/html");

ajax callback - live demo

(note that callback mode won't work on vanilla ajax or with binary files)

$.ajax({
		url: "/download.html",
		success: download.bind(true, "text/html", "dlAjaxCallback.html")
});

Binary Files

image from URL - live demo

download("/diff6.png");

Image via ajax for custom filename - live demo

var x=new XMLHttpRequest();
x.open( "GET", "/diff6.png" , true);
x.responseType="blob";
x.onload= function(e){download(e.target.response, "awesomesauce.png", "image/png");};
x.send();

Compatibility


download.js works with a wide range of devices and browsers.

You can expect it to work for the vast majority of your users, with some common-sense limits:

  • Devices without file systems like iPhone, iPad, Wii, et al. have nowhere to save the file to, sorry.
  • Android support starts at 4.2 for the built-in browser, though chrome 36+ and firefox 20+ on android 2.3+ work well.
  • Devices without Blob support won't be able to download Blobs or TypedArrays
  • Legacy devices (no a[download]) support can only download a few hundred kilobytes of data, and can't give the file a custom name.
  • Devices without window.URL support can only download a couple megabytes of data
  • IE versions of 9 and before are NOT supported because the don't support a[download] or dataURL frame locations.

FAQ


  • Can I tell when a download is done/canceled? No.
  • How can I style the temporary download link? Define CSS class styles for .download-js-link.
  • What's up with Safari? I don't know either but pull requests that improve the situation are welcome.
  • Why is my binary file corrupted? Likely: an incorrect MIME or using jQuery ajax, which has no bin support.
  • How big of files work? Depends, try yourself: File Echo Demo... I do a 1GB dl routinely on a thinkpad...

Change Log (v4.1)


  • 2008 :: landed a FF+Chrome compat way of downloading strings to local un-named files, upgraded to use a hidden frame and optional mime
  • 2012 :: added named files via a[download], msSaveBlob() for IE (10+) support, and window.URL support for larger+faster saves than dataURLs
  • 2014 :: added dataURL and Blob Input, bind-toggle arity, and legacy dataURL fallback was improved with force-download mime and base64 support
  • 2015 :: converted to amd/commonJS module with browser-friendly fallback
  • 2015 :: 4.1 added direct URL downloading via a single URL argument.
  • 2016 :: 4.2 added large dataURL support, a more semantic codebase, and hidden temp links
  • 2017 :: added support for empty dataURLs
  • 20XX :: ???? Considering Zip, Tar, and other multi-file outputs, Blob.prototype.download option, and more, stay tuned folks.