FileReader

411 阅读2分钟
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>web work</title>
</head>

<body>
  <div>
    <input type="file" id="ipt">
  </div>
  <div class="box">
    <img src="" alt="">
  </div>
</body>
<script>
  // 主线程采用new命令,调用Worker()构造函数,新建一个 Worker 线程。
  const work = new Worker('./work.js');
  // 主线程调用worker.postMessage()方法,向 Worker 发消息。
  work.postMessage({
    data: 'hello word'
  });
  // 主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息。
  work.onmessage = ({ data }) => {
    console.log(data);
  }
  // Worker 完成任务以后,主线程就可以把它关掉。
  // work.terminate();
  // 主线程可以监听 Worker 是否发生错误
  work.addEventListener('error', () => {
    console.log('web work 发生错误');
  });
  // 使用完毕,为了节省系统资源,必须关闭 Worker。

  const ipt = document.querySelector('#ipt');
  ipt.addEventListener('change', function () {
    const file = ipt.files[0];
    // FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
    // const reader = new FileReader();
    // reader.readAsArrayBuffer(file);
    // // reader.readAsText(file);
    // // 开始读取指定的 Blob中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象.
    // reader.onload = function (e) {
    //   console.log('读取的文件ArrayBuffer', e, e.target.result);
    //   const result = e.target.result;
    //   const list = new Uint8Array(result);
    //   // Array.from(list).forEach(el => {
    //   //   const item = new TextDecoder('gb2312').decode(el);
    //   //   console.log(item);
    //   // });
    //   const data = new TextDecoder('UTF-8').decode(list);
    //   console.log(data);
    //   // document.querySelector('.box').innerHTML = data;
    // };
    // const reader2 = new FileReader();
    // reader2.readAsText(file, 'utf-8');
    // reader2.onload = function (e) {
    //   const data = e.target.result;
    //   console.log('-------------------');
    //   console.log(data);
    //   document.querySelector('.box').innerHTML = data;
    // };

    const reader3 = new FileReader();
    reader3.readAsDataURL(file);
    reader3.onload = function (e) {
      const data = e.target.result;
      document.querySelector('.box img').src = data;
    };
  });
</script>

</html>
// Worker 线程内部需要有一个监听函数,监听message事件
self.addEventListener('message', ({ data }) => {
  console.log('主线程发过来的消息:', data);
  self.postMessage('你好啊');
  // setInterval(() => {
  //   self.postMessage(Math.random());
  // }, 1000 * 5);
}, false);

// self代表子线程自身,即子线程的全局对象
// self.close()用于在 Worker 内部关闭自身
// Worker 内部如果要加载其他脚本,有一个专门的方法importScripts()。
// importScripts('script1.js');
// 该方法可以同时加载多个脚本。
// importScripts('script1.js', 'script2.js');
// 数据通信
// 前面说过,主线程与 Worker 之间的通信内容,可以是文本,也可以是对象。需要注意的是,这种通信是拷贝关系,即是传值而不是传址,Worker 对通信内容的修改,不会影响到主线程。事实上,浏览器内部的运行机制是,先将通信内容串行化,然后把串行化后的字符串发给 Worker,后者再将它还原。

// 主线程与 Worker 之间也可以交换二进制数据,比如 File、Blob、ArrayBuffer 等类型,也可以在线程之间发送。下面是一个例子。


// // 主线程
// var uInt8Array = new Uint8Array(new ArrayBuffer(10));
// for (var i = 0; i < uInt8Array.length; ++i) {
//   uInt8Array[i] = i * 2; // [0, 2, 4, 6, 8,...]
// }
// worker.postMessage(uInt8Array);

// // Worker 线程
// self.onmessage = function (e) {
//   var uInt8Array = e.data;
//   postMessage('Inside worker.js: uInt8Array.toString() = ' + uInt8Array.toString());
//   postMessage('Inside worker.js: uInt8Array.byteLength = ' + uInt8Array.byteLength);
// };
// 但是,拷贝方式发送二进制数据,会造成性能问题。比如,主线程向 Worker 发送一个 500MB 文件,默认情况下浏览器会生成一个原文件的拷贝。为了解决这个问题,JavaScript 允许主线程把二进制数据直接转移给子线程,但是一旦转移,主线程就无法再使用这些二进制数据了,这是为了防止出现多个线程同时修改数据的麻烦局面。这种转移数据的方法,叫做Transferable Objects。这使得主线程可以快速把数据交给 Worker,对于影像处理、声音处理、3D 运算等就非常方便了,不会产生性能负担。

// 如果要直接转移数据的控制权,就要使用下面的写法。


// // Transferable Objects 格式
// worker.postMessage(arrayBuffer, [arrayBuffer]);

// // 例子
// var ab = new ArrayBuffer(1);
// worker.postMessage(ab, [ab]);