2017-01-28 3 views
0

다음 코드는 파일을 읽는 작업을 담당합니다. 필자가 요구하는 것은 부모 함수 (readmultifiles)에서 약속을 반환하거나 해결할 수 있도록 모든 파일을 읽었는지 확인하는 방법입니다. 코드 위모든 파일을 읽었 음을 확인하고 약속을 해결하는 방법

 $.when(readmultifiles(files)) 
       .then(function(){//all files uploaded})) 

읽기 파일을 시작합니다. 모든 파일을 읽은 후 콜백이 완료되거나 돌아올 수 있도록 수행 할 수있는 작업.

 function readmultifiles(files) {    
      // Read first file 
      setup_reader(files, 0); 
     } 


     function setup_reader(files, i) { 
      var file = files[i]; 
      var name = file.name; 
      var reader = new FileReader(); 
      reader.onload = function(e) { 
       readerLoaded(e, files, i, name); 
      }; 
      reader.readAsBinaryString(file); 
      // After reading, read the next file. 
     } 

     function readerLoaded(e, files, i, name) { 
      // get file content 
      var bin = e.target.result; 
      // do sth with text 


      // If there's a file left to load 
      if (i < files.length - 1) { 
       // Load the next file 
       setup_reader(files, i + 1); 
      } 
     } 
+2

[이 질문에 대한 답변은 '$ .when()'] (http://stackoverflow.com/questions/25613624/q-promise-difference-between-when-and-then/25614136#25614136)과이 [Tried' $ .when()'및 행운 없음] (http://stackoverflow.com/questions/24549066/tried-when-and-then-no-lucky/24549220#24549220). 기본 비동기 작업이 완료되면 해결되는 일련의 약속을 전달해야합니다. 그것은 그 자체로 모든 것을 할 수있는 마법의 힘이 없습니다. 모든 일은 약속의 그룹을 감시합니다. 이 기능을 사용하려면 비동기 작업에서 약속을 사용하고 해결할 수 있습니다. – jfriend00

+0

안녕 jFriend, 내 대답을 확인해 주시겠습니까? –

답변

2

구현이 배울 수있는 약속을 사용하여 좋은 디자인에서 고려해야 할 몇 가지가 있습니다에 코드 구조를 변경하는 경우 :

  1. 최저 수준에서 promise ("promisify"라고 함)를 만듭니다. 동기화 작업. 그런 다음 약속 기능을 사용하여 논리 흐름을 제어하고 오류를 전파 할 수 있으며 코드가 약속으로 일관되게 구현됩니다. 이 경우 readFile()을 반드시 알려야 함을 의미합니다. 또한 readFile()을 프로젝트 나 향후 프로젝트에서 더욱 유용하게 만듭니다.
  2. 항상 오류를 올바르게 전파하는지 확인하십시오. 약속을 사용하지 않을 때 비동기 코드를 사용하면 원래 호출자에게 오류를 제대로 가져 오기가 어려울 수 있습니다. 특히 비동기 논리가 복잡해지면 (중첩 또는 시퀀스 작업으로) 복잡합니다.
  3. 비동기 작업이 시퀀스 여야하는지 또는 병렬로 실행할 수 있는지 여부를 신중하게 고려하십시오. 한 작업이 다른 작업에 종속되지 않고 여러 요청으로 일부 서비스에 과부하가 걸리지 않으면 병렬 처리를 통해 결과를 더 빠르게 얻을 수 있습니다.
  4. 호출자는 작업이 완료된 시점을 알 수 있고 비동기 결과에 액세스 할 수 있도록 비동기 함수로부터의 약속을 반환합니다.
  5. 기존 약속을 불필요하게 다른 약속으로 만들지 마십시오 (약속 방지 패턴 중 하나로 간주).
  6. jQuery 약속을 사용하는 경우 약속 표준과 호환되는 jQuery 기능을 계속 사용하여 향후 상호 운용성 문제가 발생하지 않도록하고 표준 약속이 작동하는 방식을 더 잘 알고있는 독자의 코드를 혼동하지 않도록하십시오.

이 모든 것을 감안할 때 표준 약속을 사용하고 jQuery 약속을 사용하고 작업 순서를 사용하거나 병렬로 실행하고 Bluebird 약속을 사용하여 코드를 구현하는 5 가지 방법이 있습니다. 모든 경우에 결국 순서대로 배열을 얻게됩니다.

Promisify readFile() 사용하여 표준 약속

먼저, "promisify"하자 당신이 다음 일을 제어 할 약속 로직을 사용할 수 있도록 ReadFile을 작업.표준 약속

function readFile(file) { 
    return new Promise(function(resolve, reject) { 
     var reader = new FileReader(); 
     reader.onload = function(e) { 
      resolve(e.target.result); 
     }; 
     reader.onerror = reader.onabort = reject; 
     reader.readAsBinaryString(file); 
    }); 
} 

, 병렬로 모든 파일 작업을 실행하려면 모든 결과를 반환하고 표준 약속을 사용하려면 병렬

의 모든 동작을, 당신은이 작업을 수행 할 수 있습니다

function readmultifiles(files) { 
    return Promise.all(files.map(readFile)); 
} 

// sample usage 
readmultifiles(arrayOfFiles).then(function(results) { 
    // all results in the results array here 
}); 

표준 약속으로 모든 작업은 순서대로 수행됩니다.

모든 파일 작업을 순차적으로 실행하려면 (원래 코드가 순차적으로 작업 했음에도 불구하고 모든 작업이 개별적이기 때문에 여기에서 수행해야하는 것처럼 보이지 않음) 모든 결과를 순서대로 반환하고 표준 약속을 사용할 수 있습니다. 이 작업을 수행. 여기에,

function readmultifiles(files) { 
    var results = []; 
    files.reduce(function(p, file) { 
     return p.then(function() { 
      return readFile(file).then(function(data) { 
       // put this result into the results array 
       results.push(data); 
      }); 
     }); 
    }, Promise.resolve()).then(function() { 
     // make final resolved value be the results array 
     return results; 
    }); 
} 

// sample usage 
readmultifiles(arrayOfFiles).then(function(results) { 
    // all results in the results array here 
}); 

그리고 : 시퀀싱

이를 다소 표준 설계 패턴은 체인의 순서 아래로 한 번에 하나씩 실행되도록 함께 배열 체인 모든 작업을 통해 시퀀스 .reduce()를 사용 그것은 jQuery를 jQuery를 약속 사용

Promisify readFile()을 약속 사용하여 어떻게 보일지 :

function readFile(file) { 
    return new $.Deferred(function(def) { 
     var reader = new FileReader(); 
     reader.onload = function() { 
      def.resolve(e.target.result); 
     }; 
     reader.onerror = reader.onabort = def.reject; 
     reader.readAsBinaryString(file); 
    }).promise(); 
} 

jQuery를 가진 병렬 실행 :

function readmultifiles(files) { 
    return $.when.apply($, files.map(readFile)); 
} 

// sample usage 
readmultifiles(arrayOfFiles).then(function() { 
    var results = Array.prototype.slice(arguments); 
    // all results in the results array here 
}); 

그리고는, 완성도, jQuery를

function readmultifiles(files) { 
    var results = []; 
    files.reduce(function(p, file) { 
     return p.then(function() { 
      return readFile(file).then(function(data) { 
       // put this result into the results array 
       results.push(data); 
      }); 
     }); 
    }, $.Deferred().resolve()).then(function() { 
     // make final resolved value be the results array 
     return results; 
    }); 
} 

// sample usage 
readmultifiles(arrayOfFiles).then(function(results) { 
    // all results in the results array here 
}); 

블루 버드 구현

으로 순차적으로 실행하고, I 약간을 사용하는 모습을 보여 줄 테니 more advanced promise library like Bluebird 그쪽으로 여기에 유용한 추가 기능이 있습니다. 병렬 코드와 readFile()의 구현 표준 약속과 동일하지만, 순차적 구현을 ​​위해, 그것은 순서 비동기 작업에 대한 몇 가지 내장 된 블루 버드 작업을 활용할 수 있으며, 단지 구성 것이다 :

function readmultifiles(files) { 
    return Promise.mapSeries(files, readFile); 
} 

// sample usage 
readmultifiles(arrayOfFiles).then(function(results) { 
    // all results in the results array here 
}); 
+0

자세한 설명은 jFriend에게 감사드립니다.내가 이것을 통해 가서 업데이 트됩니다. –

+0

와우. js 성경을 읽는 것과 같았습니다. 이러한 것들은 저에게 새로운 것입니다. 문 열어 줘서 고마워. –

0

내가이

$.when(readmultifiles(files)).then(
         function(status) { 
          alert(status + ", things are going well"); 
         }, 
         function(status) { 
          alert(status + ", you fail this time"); 
         }, 
         function(status) { 
          $("body").append(status); 
         } 
       ); 
     function readmultifiles(files) { 

      var dfrd = $.Deferred(); 
      // Read first file 
      setup_reader(files, 0); 

      function setup_reader(files, i) { 
       var file = files[i]; 
       var name = file.name; 
       var reader = new FileReader(); 
       reader.onload = function(e) { 
        readerLoaded(e, files, i, name); 
       }; 
       reader.readAsBinaryString(file); 
       // After reading, read the next file. 
      } 

      function readerLoaded(e, files, i, name) { 
       // get file content 
       var bin = e.target.result; 
       // do sth with text 

       namee.push(name); 
       // If there's a file left to load 
       if (i < files.length - 1) { 
        // Load the next file 
        setup_reader(files, i + 1); 
       } else { 
        dfrd.resolve(namee.join(',')); 
       } 
      } 
      return dfrd.promise(); 
     } 
+0

여기서'$ .when()'을 사용할 필요가 없습니다. 'readmultifiles (files) .then (...)'만하면됩니다. – jfriend00

+0

'then'은 언제 3 개의 콜백 인수를 취합니까? –

+0

@JaromandaX - jQuery에는 progress 콜백에 대한 세 번째 인수가 있습니다 (https://api.jquery.com/deferred.then/). 매우 비표준. 약속 세계의 나머지 부분과의 호환성을 원하면 아마 사용하지 않아야합니다. – jfriend00