2017-04-23 1 views
0

나는 이론을 거의 가지고 있지 않지만 훌륭한 세부 사항을 지키고있다. $data (변경 후 파일 입력의 event object)이 주어진 경우 dataurl (dataurljpeg)의 이미지 크기 조정 기능이 반환됩니다.이벤트 객체를 사용하는 중첩 된 FileReader onload 함수의 콜백

내 문제는 dataurl이 중첩 된 기능 내에서 업데이트되었음을 ​​알게되었습니다. 코드는 아래에 표시된대로 콘솔에 data:image/jpg;base64을 로깅하여 dataurl이 업데이트되지 않았 음을 보여줍니다.

연구는 이것이 비동기 호출 호출 때문인 것으로 나타났습니다. var는 시간이 지나면 변경되지 않고 콘솔로 이동합니다. 또한 var를 업데이트하기 위해 callback을 발행하는 표준 상황임을 알게되었습니다.

몇 가지 시도를했는데 callback을 사용하여 var를 업데이트하는 깨끗한 (또는 작동하는) 방법을 찾을 수 없습니다. 이 어딘가에 callback을 해내하는 방법을 알아내는 중간에 약자로

function clProcessImages($data) { 

     var filesToUpload = $data.target.files; 
     var file = filesToUpload[0]; 
     var canvas = document.createElement('canvas'); 
     var dataurl = 'data:image/jpg;base64'; 

     var img = document.createElement("img"); 

     var reader = new FileReader(); 
     reader.onload = function(e, callback) { 

      img.onload = function() { 

       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(img, 0, 0); 

       var MAX_WIDTH = 800; 
       var MAX_HEIGHT = 600; 
       var width = img.width; 
       var height = img.height; 

       if (width > height) { 
        if (width > MAX_WIDTH) { 
         height *= MAX_WIDTH/width; 
         width = MAX_WIDTH; 
        } 
       } else { 
        if (height > MAX_HEIGHT) { 
         width *= MAX_HEIGHT/height; 
         height = MAX_HEIGHT; 
        } 
       } 
       canvas.width = width; 
       canvas.height = height; 
       var ctx = canvas.getContext("2d"); 
       ctx.drawImage(img, 0, 0, width, height); 
       dataurl = canvas.toDataURL("image/jpeg",0.8); 
       callback(dataurl); 

      } 
      img.src = e.target.result 

     } 
     reader.readAsDataURL(file); 

     console.log(dataurl); // console log mentioned in question 
     return dataurl; 

    }; 

이 코드입니다 : 내 현재 코드를 표시 한 후 나는이에 확장됩니다. 표시된 상태에서는 콜백이 호출되지 않는다는 것을 알고 있습니다.

내 첫 번째 장애물은 나중에 reader.onload 함수를 나중에 다시 호출 할 수 없다는 것입니다. 객체가로드 될 때 특별히 발생하는 이벤트 인 것처럼 보입니다. 언제든지 수동으로 호출 할 수있는 것이 아닙니다. 가장 좋은 추측은 reader.onload이라는 새 함수를 만들어서 현재의 reader.onload 함수를 모두 포함 할 것이고 나중에 이벤트를 참조하여 건너 뛰면 callback을 발급 할 수 있습니다.

소리 이론처럼 보였지만 onload 기능이 통과하는 event object으로 막혔습니다. 위의 이론을 적용하고 onload 이벤트가 새로운 함수 readerOnLoad(e)을 호출한다고 가정합니다. 그것은 event object을 통과 할 것입니다. 그러나 나중에 콜백을 수행하려는 경우 우아한 방법으로 FileReader에서 event object을 전달할 방법이 없으므로 수동으로 readerOnLoad(e)으로 전화를 걸 수 있습니다. 해결하기 위해 매우 복잡한 코드 *로 빠져있는 것처럼 느껴지지만 너무 틈새를 느끼지 않는 상황에 조금 더 우아해야하는 것처럼 느껴집니다.

* 원래 $dataevent object 변수는 파일 입력이 변경을 감지했을 때 전역 변수를 저장함으로써 얻어졌습니다. 이론적으로, FileReader onload에 대해 event object을 저장할 전역 변수를 만들 수 있습니다. 단지 원래의 코드와이 방식으로 작동하는 코드의 차이점은 시간이 지나면 준비가되지 않은 var를 업데이트하는 것이 유일한 차이 일 때 상당히 심각하고 부끄럽다는 점에서 매우 복잡하게 느껴집니다.

답변

1

비동기 함수로 작업 할 때는 일반적으로 함수를 콜백으로 전달하려고합니다.

// asyncTask is an asynchronous function that takes 3 arguments, the last one being a callback 

asyncTask(arg1, arg2, function(err, result) { 
    if (err) return handleError(err); 
    handleResult(result); 
}) 

그래서 귀하의 경우, 당신이 할 수 있습니다 : 당신은이 같은 NodeJS 스타일의 콜백을 사용할 수 있습니다

또한 첫 번째 예와 같이 콜백에 오류 개체를 전달 할 수 있습니다
clProcessImages($data, function(dataurl) { 
    console.log(dataurl); 
    // Do you other thing here 
}); 

function clProcessImages($data, onProcessedCallback) { 
    var filesToUpload = $data.target.files; 
    var file = filesToUpload[0]; 
    var canvas = document.createElement('canvas'); 
    var dataurl = 'data:image/jpg;base64'; 

    var img = document.createElement("img"); 

    var reader = new FileReader(); 
    reader.onload = function(e) { 

    img.onload = function() { 

     var ctx = canvas.getContext("2d"); 
     ctx.drawImage(img, 0, 0); 

     var MAX_WIDTH = 800; 
     var MAX_HEIGHT = 600; 
     var width = img.width; 
     var height = img.height; 

     if (width > height) { 
     if (width > MAX_WIDTH) { 
      height *= MAX_WIDTH/width; 
      width = MAX_WIDTH; 
     } 
     } else { 
     if (height > MAX_HEIGHT) { 
      width *= MAX_HEIGHT/height; 
      height = MAX_HEIGHT; 
     } 
     } 
     canvas.width = width; 
     canvas.height = height; 
     var ctx = canvas.getContext("2d"); 
     ctx.drawImage(img, 0, 0, width, height); 
     dataurl = canvas.toDataURL("image/jpeg",0.8); 
     onProcessedCallback(dataurl); 

    } 
    img.src = e.target.result 

    } 
    reader.readAsDataURL(file); 

    return dataurl; 
}; 

, 적절하게 처리하십시오.

즉, 콜백 함수를 항상 자신의 비동기 함수에 인수로 추가하십시오.

+0

은 잘 작동하며 설명이 합리적입니다. 고마워. 한가지 특이점은'console.log' (jpeg를 포함하도록 올바르게 업데이트되었다는 것을 확인)의 직후에'form_data.append ('file', dataurl);을 추가하면 내'PHP' 핸들러가 나는 if (! file_exists ($ _ FILES [ 'file'] [ 'tmp_name']) ||! is_uploaded_file ($ _ FILES [ 'file'] [ 'tmp_name']))'을 체크한다. form_data에 추가 된 모든 것은 핸들러에서 잘 반환되지만, 폼이 ok를 보낸다는 것을 암시한다. – biscuitstack

+0

내가 가지고 있다고 생각해. 데이터 url을 다음과 같이 BLOB로 변환하면 작동합니다. http://stackoverflow.com/questions/4998908/convert-data-uri-to-file-then-append-to-formdata/5100158. 왜이 사이트의 다른 곳에서 많은 게시물이 그대로 데이터를 추가 할 것을 제안하는지 잘 모릅니다. – biscuitstack