TOP > カテゴリ > JavaScript >

Promiseを使用して複数のファイルを連続して読み込む[IE対応版]

JavaScriptの標準規格の「ECMAScript6」(2015年6月17日公開)の機能である「Promise」をInternet Explorerで使用して複数のファイルを同期のように連続して読み込むサンプルです。

Web Workerを使用した連続読み込みは「ファイルを同期・非同期で読み込む」(バイナリ用)をご覧ください。非同期を巧みに使用した読み込みは「Image.onloadを同期で読み込む」です。

Promise

PromiseオブジェクトはIEには搭載されていませんので、オープンソースのPolyfillライブラリ(ポリフィル)を使用します。PolyfillとはIEなどのブラウザで搭載されていない新機能をライブラリを使用して使用できるようにするものです。

今回、使用するのはMITライセンスの「native-promise-only」です。ファイルは「npo.src.js」で約8.7kbです。このファイルを「圧縮(minify)」すれば約3.4kbぐらいなので軽量です。

軽量だけは無く、JavaScriptの規格に沿って作成されているので「Edge/Chrome/Firefox」などのブラウザのPromiseオブジェクトと同様です。

※ブラウザにPromiseオブジェクトが既にある場合は、そちらを使用します。

ファイルを連続して読み込む 1

次のサンプルは複数の画像ファイルを連続して読み込みながら、ページ下部にcanvasを追加して読み込んだ画像を描画します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src ="npo.src.js"></script>
<script>

// 非同期で画像の読み込み
function getAsynchroImageData(file) {  

  return new Promise(function(resolve, reject) {    
    var image = new Image;
     
    // イメージが読み込まれた
    image.onload = function (){
      var canvas = document.createElement('canvas'); 
      canvas.width  = image.width;
      canvas.height = image.height;  
      
      ctx = canvas.getContext("2d");     
      ctx.drawImage(image,0,0);      

      resolve(ctx.getImageData(0, 0, image.width, image.height));
     }
      
    // イメージが読み込めない
    image.onerror  = function (){
      reject(Error('この画像は読み込めません。\n' + file.name));
    };
 
    image.src = file.data;
   });
}

// 非同期でファイルを読み込む
function getAsynchroFile(file) {  

  return new Promise(function(resolve, reject) {
    
    var reader = new FileReader();   
    reader.onload = function (event) {   
       resolve({'data':reader.result,'name':file.name});     
    }
    
    reader.onerror = function (event) {   
       reject('ファイルの読み込みに失敗しました');       
    }
    
    reader.readAsDataURL(file);     
   });
}

// ドラッグオーバー
function onDragOver(event){ 
  event.preventDefault(); 
} 
  
// ドロップ    
function onDrop(event){
  onAddFile(event);
  event.preventDefault(); 
}  

// ユーザーによりファイルが追加された  
function onAddFile(event) {
  var files;
  
  if(event.target.files){
    files = event.target.files;
  }else{ 
    files = event.dataTransfer.files;   
  }    
  
  // 連続してファイルを読み込む
  for(var i=0;i<files.length;i++){
    
    // ファイルの読み込み
    getAsynchroFile(files[i]).then(function(file){
    
      // 画像の読み込み
      getAsynchroImageData(file).then(function(imagedata){
      
        // canvasを生成してImageDataを描画する
        var canvas = document.createElement('canvas'); 
        canvas.width  = imagedata.width;
        canvas.height = imagedata.height;  
       
        ctx = canvas.getContext("2d"); 
        ctx.putImageData(imagedata,0,0);    
        
        document.body.appendChild(canvas);

      // エラー(画像の読み込み失敗)
      }).catch(function(err){
        alert(err);        
      });  
    
    // エラー(ファイルの読み込み失敗)
    }).catch(function(err){
       alert(err);  
    });
  }  
}   
</script>
</head>
<body ondrop="onDrop(event);" ondragover="onDragOver(event);">  
<h4>画像の読み込み (複数可能)</h4>
<p></p>
<input type="file" id="inputfile" accept="image/jpeg,image/png,image/gif,image/bmp" multiple onchange="onAddFile(event);">
<p></p>
</body>
</html> 

ファイルを連続して読み込む 2

今度は「1」のサンプルを改良したものです。結果は同じですのでお好きな方を使用してください。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src ="npo.src.js"></script>
<script>

// 非同期で画像の読み込み
function getAsynchroImageData(file) {  

  return new Promise(function(resolve, reject) {    
    var image = new Image;
     
    // イメージが読み込まれた
    image.onload = function (){
      var canvas = document.createElement('canvas'); 
      canvas.width  = image.width;
      canvas.height = image.height;  
      
      ctx = canvas.getContext("2d");     
      ctx.drawImage(image,0,0);      

      resolve(ctx.getImageData(0, 0, image.width, image.height));
     }
      
    // イメージが読み込めない
    image.onerror  = function (){
      reject(Error('この画像は読み込めません。\n' + file.name));
    };
 
    image.src = file.data;
   });
}

// 非同期でファイルを読み込む
function getAsynchroFile(file) {  

  return new Promise(function(resolve, reject) {
    
    var reader = new FileReader();   
    reader.onload = function (event) {   
       resolve(getAsynchroImageData({'data':reader.result,'name':file.name}));     
    }
    
    reader.onerror = function (event) {   
       reject('ファイルの読み込みに失敗しました');       
    }
    
    reader.readAsDataURL(file);     
   });
}

// ドラッグオーバー
function onDragOver(event){ 
  event.preventDefault(); 
} 
  
// ドロップ    
function onDrop(event){
  onAddFile(event);
  event.preventDefault(); 
}  

// ユーザーによりファイルが追加された  
function onAddFile(event) {
  var files;
  
  if(event.target.files){
    files = event.target.files;
  }else{ 
    files = event.dataTransfer.files;   
  }    
  
  for(var i=0;i<files.length;i++){
    
    // ファイル(画像)の読み込み
    getAsynchroFile(files[i]).then(function(imagedata){
    
      // canvasを生成してImageDataを描画する
      var canvas = document.createElement('canvas'); 
      canvas.width  = imagedata.width;
      canvas.height = imagedata.height;  
     
      ctx = canvas.getContext("2d"); 
      ctx.putImageData(imagedata,0,0);    
      
      document.body.appendChild(canvas);
    
    // 読み込み失敗
    }).catch(function(err){
       alert(err);  
    });
  }  
}   
</script>
</head>
<body ondrop="onDrop(event);" ondragover="onDragOver(event);"> 
<h4>画像の読み込み</h4>
<p></p>
<input type="file" id="inputfile" accept="image/jpeg,image/png,image/gif,image/bmp" multiple onchange="onAddFile(event);">
<p></p>
</body>
</html> 

Promiseに関しては次のリンク先で詳細を確認して下さい。

Promise関連リンク(外部)

JavaScript Promiseの本
JavaScript Promises
Promise (MDN)
Promise クラスについて
今更だけどPromise入門





関連記事



公開日:2016年05月24日
記事NO:01976