XHR 진행표시와 편리한 파일 업로드 피드백

이 글은 XHR progress and rich file upload feedback에 대한 번역 및 편집본입니다.

오늘날 웹에서는 파일 업로드를 할 때 리치 인터페이스를 제공하는 위젯에 대한 공통적인 제약점을 가지고 있다. 많은 사이트들이 Flash 혹은 데스크탑 어플리케이션을 이용하여 파일을 업로드할 때 보다 나은 사용자 경험을 제공하고 있다.

Firefox 3.5에서는 더 나은 프로그레스 표시바를 만들 수 있도록 이러한 격차 중 하나를 중개해준다. 많은 개발자들은 파일 업로드를 할 때 Firefox File 객체(nsIDOMFile)와 XMLHttpRequest를 같이 사용할 수 있다는 사실을 모르고 있다. 이 데모에서는 사용자에게 업로드 상태를 예측할 수 있게끔 피드백을 주는 것 뿐만 아니라, 여러개의 파일을 동시에 빠르고 쉽게 올릴 수 있는 위젯에 대해 설명을 한다.

Progress Indicator
현재 어플리케이션이 요청한 작업을 할 수 없거나 현재 진행 중인 작업이 완료될 것 같으면 사용자에게 피드백을 주는 것이 좋다. 피드백을 주는 대표적인 두가지 방식으로는 다음과 같이 있다.

* 가늠할 수 없는 프로그레스 – 어떤 작업이 방금 수행됬습니다.
* 가늠 할 수 있는 프로그레스 – ‘40% 완료 되었습니다.’, ‘42% 완료 되었습니다’ 등등..

데모 Deterministicasaidwhat?
파일 업로드/다운로드 상태의 프로그레스 바를 띄어주는 간단한 페이지를 만들었다.

데모는 mozilla.pettay.fi 에 호스팅되어 있고, Firefox3.5 beta4 혹은 그 이후 버전에서 동작한다. 여기서는 여러 개의 파일이 따로 폼을 등록하거나 현재 페이지를 벗어나지 않고 어떻게 동시에 업로드될 수 있는지 보여준다. 각각의 파일이 업로드 / 다운로드될 때 현재 속도, 완료률(%) 그리고 전송된 바이트 크기를 보여준다. 이제 이 페이지에서 사용했던 코드 중 몇몇 부분을 살펴보자. “데모(http://mozilla.pettay.fi/xhr_upload/xhr_file_upload_demo_with_speed.html)” 를 클릭하여 데모 페이지로 이동한 후 페이지 소스 보기를 통하여 전체 코드를 살펴보자.

이 페이지에는 2개의 HTML 태그가 있다. 하나는 type=”file”이고 다른 하나는 type=”button” 이다. 폼은 버튼에 onclick 핸들러를 추가하지 않는 이상 전송되지 않는다.

<input type="file" id="file">
<input type="button"
          onclick="startXHR();"
          value="Upload file using XHR">

startXHR 함수에서 XMLHttpRequest를 만들고 새로이 ‘프로그레스’ 이벤트를 받기 위해 XHR 요청에 이벤트 핸들러를 등록했다. ProgressEvent의 lengthComputable 프로퍼티를 통해 가늠할 수 있는 프로그레스 인지 아니면 가늠할 수 없는 프로그레스인지 알 수 있게된다. 또한 파일의 전체 크기와 업로드된 바이트 크기를 알 수 있다.

var xhr = new XMLHttpRequest();

xhr.onprogress = function(evt) {        
if (evt.lengthComputable) {
    evt.target.curLoad = evt.loaded;
    evt.target.log.parentNode.parentNode.previousSibling.textContent =
        Number(evt.loaded/k).toFixed() + "/"+ Number(evt.total/k).toFixed() + "kB";
}
if (evt.lengthComputable) {
    var loaded = (evt.loaded / evt.total);
    if (loaded < 1) {
        var newW = loaded * width;
        if (newW < 10) newW = 10;
            evt.target.log.style.width = newW + "px";
        }
    }
};

이제 우리는 전송을 할 데이터가 필요하다. input의 id를 통해 바로 전송할 파일을 가져왔다.

var files = document.getElementById("file").files;
if (files) {
   var file = files.item(0);
   xhr.sendAsBinary(file.getAsBinary());

마지막으로 실제 요청을 보내 보자.

xhr.open("POST", "cgi-bin/posthandler.pl");
xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
xhr.sendAsBinary(file.getAsBinary());

이 메소드들은 xhr.upload.onprogress와도 동작할 것이다.
XMLHttpRequest 객체의 sendAsBinary 메소드와 File 객체의 getAsBinary 메소드를 사용한 것을 눈여겨 보자. Firefox 3 에 와서는 클라이언트 쪽에서 폼 전송을 통하지 않고도 파일을 전송할 수 있게
되었다. 기존의 input 과 폼 전송보다 이를 사용하는 것이 더 유용하다. 뿐만 아니라 다음 번 W3C 표준으로 채택되었다.

nsIDOMFile이 제공하는 연관된 메소드로는 자르고, 표시하는데 편리한 DOMString을 리턴해주는 getAsText 메소드가 있다.

데모에는 사용되지 않았지만, nsLDOMFile에 관한 예제 하나를 보여준다.

file.getAsText("utf8");

위에서 보여준 파일 업로드에 관한 예제는 요지만 보여준 코드이다. “데모에서 전체 코드”(링크 : http://mozilla.pettay.fi/xhr_upload/xhr_file_upload_demo_with_speed.html) 를 살펴보길 바란다.

Feedback In User Interfaces
시스템이 피드백을 주면 사용자가 지각하는데 큰 도움을 준다. 우리는 항상 어떤 작업이 얼마나 걸릴지 판단하기 힘들다. 따라서 최소한으로 가늠할 수 없는 프로그레스 바라도 표시를 해주어야 한다.

파일을 업로드 / 다운로드 하는 동안 (서버가 Content-Length를 주었다는 가정 하에) 우리는 확실히 전체 바이트 크기를 알고 있어야 한다. Firefox 3.5의 ProgressEvents 는 프로그레스 이벤트를 추가하여 정확한 업로드/다운로드 프로그레스 상태를 볼 수 있도록 해준다.

전통적으로 XMLHttpRequest로는 가늠할 수 있는 프로그레스를 만들기는 어렵다. 이론적으로 콜백으로 상태 코드와 업데이트 된 문자들을 받아와 표시를 했는데, 그리 효율적이지 못하다. 과거에는 가늠할 수 있는 프로그레스 바가 중요하다면, 매초마다 상태값을 받아오는 XHR 요청을 보내야만 했다.

Enter Progress Events
W3C에서 Firefox 3.5에 포함된 Progress Events 1.0 의 초안을 작성하고 있다. Firefox는 새로운 DOM ~ . 그 외 error, abort 그리고 load 같은 존재했던 다른 이벤트들도 포함됬다.

이 이벤트들은 업로드와 다운로드 때 모두 가능하다. 프로그레스 이벤트는 다음과 같은 프로퍼티를 제공한다.
* lengthComputable – 요청의 크기를 알 수 있는지 여부
* loaded – 전송된 바이트의 크기
* total – 요청의 전체 바이트 크기

The Contract
프로그레스 이벤트의 프로퍼티들을 살펴보면, 여기에 적용된 룰들이 있다.
* lengthComputable이 false면, total 프로퍼티 값은 0가 된다.
* loadstart 이벤트는 항상 한 번만 호출된다.
* progress 이벤트는 loadstart 이벤트가 호출된 이후 0번 혹은 여러번 호출된다.

“이것이 다입니다”(링크 : http://mozilla.pettay.fi/xhr_upload/xhr_file_upload_demo_with_speed.html). Firefox 3.5 를 이용하여 보다 향상된 파일 업로드를 구현해 보세요.

작성자: keepdelight

keepdelight가 작성한 문서들…


댓글이 없습니다.

댓글 쓰기