LoginSignup
1
0

More than 1 year has passed since last update.

WebWorker上でS3にファイルをアップロードするときに困ったグローバルオブジェクト

Last updated at Posted at 2021-12-20

本稿はWano Group Advent Calendar 2021 用の記事となります。

経緯/書くこと

大きいサイズのファイルをWebブラウザからS3に上げるには、マルチパートアップロードする
必要があります。
この時、ブラウザによってはUIスレッドをブロックするケースがあり、対策としてWeb Worker上でのファイル部分読み出しとマルチパートアップロードを試すケースがありました。

事象自体はけっこう前なので状況が変わっている可能性もありますが、備忘録がてらそのときやったことをメモします。

web workerとは

ウェブ ワーカーの基本
シングルスレッドなjavascriptの世界において、独立したスレッドを実現するものです。

aws sdk console 上で直接ファイルをuploadするときも、WebWorkerが使われているのが確認できます.

image.png

uploadするためのモジュールの構成

ブラウザから s3 multi part upload する方法自体の手順は、STSやaws-sdk-jsを使った場合だと

  • 1. サーバーサイドで aws sts 系のモジュールで Upload用一時ロールを発行
  • 2. フロントエンドで aws-sdk/clients/s3 などで
    • createMultipartUpload
    • localのfile object を file.slice(rangeStart, end); などで部分読み出ししつつuploadPart
    • 全て終わったら completeMultipartUpload

のようになります。
このへんは最近はsdkでも S3.ManagedUploadとかでうまくやってくれるのかも?
本題は、これをどうweb worker版に落とし込むか。

image.png

こうなりました。

ポイントとしては、

  • postMessageをうまく使って Main Thread側のモジュールとWeb Worker側でイベント登録<->コールバックの関係性を作る
  • file object自体はMain Thread側で読んだものが直接web worker側に渡せるのでそれを使う です。

綺麗にうまくいった!と思ったものの...

Web Worker上にないグローバルオブジェクトがある

ブラウザ版 aws-sdk-js はwindowオブジェクトへのアクセスやdocumentオブジェクトへのアクセスを行うようで、
実際に使うといろいろエラーが出てしまいました。

エラーメッセージに従って当時愚直に潰したものが下記です...

import { DOMParser } from '@xmldom/xmldom';

// @ts-ignore
global["window"] = {};
global["window"].DOMParser = DOMParser;
global["DOMParser"] = DOMParser;

// @ts-ignore
global["document"] = {
  cookie: "",
  createElement: function() {
    // @ts-ignore
    let href = string || undefined;

    const elm: any = {
      set href(url: string) {
        const obj = new URL(url);
        elm.protocol = obj.protocol;
        elm.hostname = obj.hostname;
        elm.pathname = obj.pathname;
        elm.port = obj.port;
        elm.search = obj.search;
        elm.hash = obj.hash;
        elm.host = obj.host;
        href = url;
      },
      get href() {
        // @ts-ignore
        return href;
      },
      protocol: undefined,
      hostname: undefined,
      pathname: undefined,
      port: undefined,
      search: undefined,
      hash: undefined,
      host: undefined
    };

    return elm;
  }
};

(ignoreやらanyばかりでtsの意味がない点は本題じゃないので今回ご容赦)
Web Worker には windowオブジェクトやらdocumentオブジェクトやらがないそうなので、aws-sdk-jsが使う最低限の仕様をグローバルに定義しています。

唯一、DOMParser というモジュールは下記のものが使えました。

npm install --save @xmldom/xmldom @types/xmldom
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0