• 목록
  • 아래로
  • 위로


        obj.on('drop', function (e) {
            e.preventDefault();
            var files = e.originalEvent.dataTransfer.files;
            for (var i = 0; i < files.length; i++) {
                ext = files[i].name.split('.').pop();
                if (ext != 'jpg' && ext != 'jpeg' && ext != 'png' && ext != 'gif') {
                    alert(ext + ' filetype is not allowed!');
                    throw new Error('Filetype error.');
                }
            }
            if(files.length < 1)
                return;
                                     
            for (var i = 0; i < files.length; i++) {
                var data = new FormData(); // 이 부분에 대해 질문을 드립니다!!!
                data.append('up_load', files[i]);
                $.ajax({
                    url: '/bbs/dropbox.php',
                    method: 'post',
                    data: data,
                    async: true,
                    processData: false,
                    contentType: false,
          success : function(datas) {
            $('#dropzone')
                        .css('border', '1px dashed blue')
                        .css('cursor', 'pointer');
        $("input#file").val("");
        var filename = datas.match(/.*?_.*?_(.+)\?raw=1/)[1];
        $("#img_list").append("<img src='" + datas + "' class='dropbox_upload' data-toggle='tooltip' data-placement='bottom' title='" + filename + "' />");
        img_focus();
                    }
                });
            }
        })



안녕하세요?


자바스크립트의 FormData와 관련하여 질문 드립니다.


API가 멀티파일 업로드를 허용하지 않는 상황에서 위와 같은 방식으로 복수의 파일을 drag & drop을 하면 


for문으로 ajax를 돌려서 하나씩 파일을 전송하려고 하는데요.



원래는 var data = new FormData();를 for문 밖에 놓고 


data.set('up_load', files[i]);라고 하여 값을 덮어썼는데요.


모던 브라우저에서는 문제가 없는데 IE에서 작동을 안 하길래 확인해보니 IE에서는 set 메서드를 지원하지 않네요 ㅠㅠ

(IE 11에서 테스트했습니다)


게다가 IE에서는 delete 메서드도 지원하지 않구요.



그래서 IE의 호환성 때문에 부득이 다음과 같이 for문을 돌릴 때마다 data 변수를 새로 생성하는 방식을 택했는데 이것이 최선의 방법일까요?


var data = new FormData();

data.append('up_load', files[i]);


제가 자바스크립트 & jQuery 실력이 부족하다보니 보다 효율적인 방법이 있을 것 같아서 여쭤봅니다 ^^


이런 부분의 처리와 관련하여 넓은 의미에서의 코딩 컨벤션이 있을 것 같아서요.



그럼 폭염경보가 발령되었다는데 건강 유의하시고 좋은 오후 되시고, 이번 한 주도 화이팅입니다 ^-^


답변 달아주실 부들께 미리 감사드려요~



https://developer.mozilla.org/ko/docs/Web/API/FormData



작성자
이니스프리 119 Lv. (2%) 4161690/115200000EXP

Make StudyForUs Great Again!

 

CSVpuymXAAAVVpd.jpg

댓글 6

Hanam09
profile image
obj.addEventListener("drop",e => {
/* Vanila JS 로 작성
 * 하지만 속도를 올려보려 할 수 있죠
 */
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
var allowedExt = /(jpg|jpeg|png|gif|webp|bmp)/i;
for (var count = 0; count < files.length; count++) {
extension = files[count].name.split(".").pop();
if (!allowed.test(extension)) {
window.alert(extension+" filetype isn't allowed!");
throw new Error("Filetype Error.");
}
}
if (files.length < 1) return;

for (var i = 0; i < files.length; i++) {
var data = new FormData();
var xmlHttp = new XMLHttpRequest();
data.append("up_load",files[i]);
xmlHttp.open("POST","/bbs/dropbox.php",true);
xmlHttp.send(data);
xmlHttp.onreadystatechange = function() {
if (this.readyState === this.DONE && this.status === 200) {
var filename = this.response.match(/.*?_.*?_(.+)\?raw=1/)[1];
document.getElementById('dropzone').style.border = "1px dashed blue";
document.getElementById('dropzone').style.cursor = "pointer";
document.querySelector('input#file').value = "";
document.getElementById('img_list').innerHTML += "<img src='" + this.responseText + "' class='dropbox_upload' data-toggle='tooltip' data-placement='bottom' title='" + filename + "'>";
img_focus();
}
}
}
});



음  값을 바꾸긴 어렵겠네요!




comment menu
2019.08.05. 23:40

신고

"Hanam09님의 댓글"

이 댓글을 신고 하시겠습니까?

이니스프리 작성자 → Hanam09
profile image

안녕하세요?
날씨도 덥고 바쁘신데 바닐라 자바스크립트로 다시 작성해주셔서 감사합니다!!

formdata에 append 메서드를 사용하는 것이 IE의 호환성 관련하여 최선이라는 말씀이시죠? ^^


개발자분들의 커뮤니티에 올라오는 글을 보면 요샌 jQuery를 버리려는 경향이 있더군요~

저는 빠른 개발(이라고 쓰지만 실제로는 개발할 능력이 안 되어서 구글링 후 복붙)을 하느라  jQuery를 불필요하게 남발한 것 같네요.

덕분에 많이 배우고 갑니다 ^-^


+)

아참 죄송한데 하나만 더 여쭤볼게요~


for문 안에 ajax의 success가 들어가서 발생하는 문제 같은데요.

$('#dropzone') 

    .css('border', '1px dashed blue') 

    .css('cursor', 'pointer');

이 부분 때문에 여러 개의 파일 중에 하나만 전송이 완료되어도 CSS 속성이 변경되는데요.

혹시 여러 개의 파일 모두가 전송이 완료된 후에 CSS 속성을 변화시키는 방법이 있을까요?


$.ajax를 사용해서 통신을 하면 $.ajax가 가장 마지막에 호출되어 동작하기 때문인지

$.ajax가 포함된 for문의 뒤에 $("body").css("cursor", "default");을 넣으면 

커서가 progress로 아예 바뀌지 않는 것처럼 보이더군요 ㅠㅠ

comment menu
2019.08.06. 00:19

신고

"이니스프리님의 댓글"

이 댓글을 신고 하시겠습니까?

Hanam09 → 이니스프리
profile image

XHR을 HTTP synchronous request 요청을 사용하면 구현이 정말 쉽지만 AJAX를 사용하면  비동기라는 특성때문에 구현이 약간 힘듭니다.


obj.addEventListener("drop",e => {
/* Vanila JS 로 작성
 * registedLastReq라는 전역변수로 for문의 마지막에서 Ajax의 전송대기열에 올린것을 선언하고 success에서 이를 구별함.
 */
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
var allowedExt = /(jpg|jpeg|png|gif|webp|bmp)/i;
registedLastReq = false;
for (var count = 0; count < files.length; count++) {
extension = files[count].name.split(".").pop();
if (!allowed.test(extension)) {
window.alert(extension+" filetype isn't allowed!");
throw new Error("Filetype Error.");
}
}
if (files.length < 1) return;

for (var i = 0; i < files.length; i++) {
var data = new FormData();
var xmlHttp = new XMLHttpRequest();
data.append("up_load",files[i]);
xmlHttp.open("POST","/bbs/dropbox.php",true);
xmlHttp.send(data);
if (i == files.length-1)
registedLastReq = true;

xmlHttp.onreadystatechange = function() {
if (this.readyState === this.DONE && this.status === 200) {
var filename = this.response.match(/.*?_.*?_(.+)\?raw=1/)[1];
document.querySelector('input#file').value = "";
document.getElementById('img_list').innerHTML += "<img src='" + this.responseText + "' class='dropbox_upload' data-toggle='tooltip' data-placement='bottom' title='" + filename + "'>";
img_focus();
if (registedLastReq) {
document.getElementById('dropzone').style.border = "1px dashed blue";
document.getElementById('dropzone').style.cursor = "pointer";registedLastReq=false;
}
}
}

}
});



음.. 일단 이렇게 해봤어요... 


이 코드의 문제점은 이 Ajax가 비동기요청으로 작동한다는 겁니다.

for 문에서 마지막 ajax전송부분까지 요청을 Send했다고 하더라도.. 

그 요청은 아직 완료된게 아닙니다. 요청대기열에 올렸을 뿐이죠...

그래서 마지막 요청을 요청대기열에 올리고 registedLaseReq라는 변수를 선언하여 success될때 이를 구별한다 하더라도 마지막 요청의 앞에

대기타고있는 요청이 있다면 그 요청이 이 변수를 가로채서(...) 완료되었다고 치고 스타일을 바꿀 수 있는거죠....


그래서 이를 좀 개선한 코드를 추가해봤습니다...



obj.addEventListener("drop",e => {
/* Vanila JS 로 작성
 *
 */
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
var allowedExt = /(jpg|jpeg|png|gif|webp|bmp)/i;
for (var count = 0; count < files.length; count++) {
extension = files[count].name.split(".").pop();
if (!allowed.test(extension)) {
window.alert(extension+" filetype isn't allowed!");
throw new Error("Filetype Error.");
}
}
if (files.length < 1) return;

for (var i = 0; i < files.length; i++) {
var data = new FormData();
var xmlHttp = new XMLHttpRequest();
data.append("up_load",files[i]);
xmlHttp.open("POST","/bbs/dropbox.php",true);
xmlHttp.send(data);
if (i == files.length-1) {
xmlHttp.onreadystatechange = function() {
if (this.readyState === this.DONE && this.status === 200) {
var filename = this.response.match(/.*?_.*?_(.+)\?raw=1/)[1];
document.getElementById('dropzone').style.border = "1px dashed blue";
document.getElementById('dropzone').style.cursor = "pointer";
document.querySelector('input#file').value = "";
document.getElementById('img_list').innerHTML += "<img src='" + this.responseText + "' class='dropbox_upload' data-toggle='tooltip' data-placement='bottom' title='" + filename + "'>";
img_focus();
}
}
} else {
xmlHttp.onreadystatechange = function() {
if (this.readyState === this.DONE && this.status === 200) {
var filename = this.response.match(/.*?_.*?_(.+)\?raw=1/)[1];
document.querySelector('input#file').value = "";
document.getElementById('img_list').innerHTML += "<img src='" + this.responseText + "' class='dropbox_upload' data-toggle='tooltip' data-placement='bottom' title='" + filename + "'>";
img_focus();
}
}
}

}
});



이건 좀 무식한 방법입니다...

for문에서 if문으로 마지막 요청을 구별하여 스타일하나 바꾸기위해 통으로 복붙한 후  마지막 요청 success에 스타일을 바꾸는 코드를 삽입한겁니다.

하지만 이짓때문에  success 같은 코드가 생겼습니다.....


success에서 마지막 요청을 구별할 수 있는 방법은 없느냐? 없습니다...


이런저런 문제(비동기적  작동, 클로저)가 있어서 우리가 상상하는 코드는 못짤겄같습니다.


하지만 비동기만 포기하면 말이 좀 달라집니다.




obj.addEventListener("drop",e => {
/* Vanila JS 로 작성
 * Synchronous request
 */
e.preventDefault();
var files = e.originalEvent.dataTransfer.files;
var allowedExt = /(jpg|jpeg|png|gif|webp|bmp)/i;
for (var count = 0; count < files.length; count++) {
extension = files[count].name.split(".").pop();
if (!allowed.test(extension)) {
window.alert(extension+" filetype isn't allowed!");
throw new Error("Filetype Error.");
}
}
if (files.length < 1) return;

for (var i = 0; i < files.length; i++) {
var data = new FormData();
var xmlHttp = new XMLHttpRequest();
data.append("up_load",files[i]);
xmlHttp.open("POST","/bbs/dropbox.php",false);
xmlHttp.send(data);
if (xmlHttp.status === 200) {
var filename = this.response.match(/.*?_.*?_(.+)\?raw=1/)[1];
if (i === files.length-1) {
document.getElementById('dropzone').style.border = "1px dashed blue";
document.getElementById('dropzone').style.cursor = "pointer";
}
document.querySelector('input#file').value = "";
document.getElementById('img_list').innerHTML += "<img src='" + this.responseText + "' class='dropbox_upload' data-toggle='tooltip' data-placement='bottom' title='" + filename + "'>";
img_focus();
}
}
});


이 정도로 코드가 맑아집니다(...)


다만 동기적요청은  일부 웹 엔진에서  사용자 경험에 좋지않은 영향을  발생시킬 수 있다는 이유로 비권장 사항입니다. 다만 Naver도 씁니다.


참고로.... 동기요청에서 서버가 빨리 응답 안해주면 코드 실행자체가 얼어붙습니다.

comment menu
2019.08.06. 16:41

신고

"Hanam09님의 댓글"

이 댓글을 신고 하시겠습니까?

이니스프리 작성자 → Hanam09
profile image

오오~ 날씨도 무더운데 상세한 설명을 해주셔서 정말 감사드립니다! ^-^

바닐라 자바스크립트로 보니 코드 자체는 길어져도 오히려 이해는 쏙쏙 잘 되네요~

 

결과적으로 synchronous로 처리하면 간단히 해결되는 문제이군요 ㄷㄷ

어차피 Dropbox API가 멀티파일 업로드를 허용하지 않아서

결국 제 서버의 PHP cURL과 Dropbox 서버와의 통신은 사실상 동기적으로 이루어질텐데 말이죠.

 

이 스크립트를 작성하면서 이런저런 문제로 jQuery ajax에서 async: false로 설정을 변경한 적이 있었는데요.

(명쾌하게 이해는 안 되지만 ajax 구문만 따로 함수로 선언해서 호출할 때에는

async를 끄지 않으면 완전 뒤죽박죽이 되어버려서 부득이 false로 설정해야 되더군요 ㅜㅜ)

크롬 최신버전에서는 depreciated라는 warning이 뜨면서도 작동은 하는 경우도 있고, 아예 멈추는 경우도 있고 케바케더군요.

(제가 테스트한 환경에서는 파폭 최신버전으로는 작동은 잘 되는 것 같더군요)

이에 대해 구체적으로 크롬에서 어떤 경우에 작동을 멈추는지에 대해서는 구글링을 해봐도 명확한 답이 없더군요 ㅠㅠ

 

모든 문제는 제가 자바스크립트의 동작방식과 ajax가 어떻게 돌아가는지에 대해 잘 모르기 때문인 것 같네요.

(자꾸 PHP나 파이썬 돌아가듯이 생각하는 경향이 있어서요 ㅠㅠ)

애당초 ajax를 for문으로 반복을 돌리는 것이 아니라 선택된 여러 개의 파일을 한꺼번에 PHP로 넘기고

PHP에서 반복문으로 cURL을 돌리는 것이 보다 간명한 방법이라는 생각이 들기는 하는데

이제 와서 그렇게 수정하려면 상당히 많이 뜯어고쳐야겠네요 ㅜㅜ

 

일단 올려주신 스크립트를 바탕으로 더 공부하면서 계속 수정해보겠습니다!

책을 사놓고 제대로 읽지 못했는데 클로저에 대한 공부도 더 해야겠네요~

다시 한 번 감사드립니다 ^^

그럼 저녁식사 맛있게 드세요~

comment menu
2019.08.06. 18:23

신고

"이니스프리님의 댓글"

이 댓글을 신고 하시겠습니까?

Hanam09 → 이니스프리
profile image

음.. 제가 솔직히 말하자면... 동기요청을 추천드리지는 않습니다.

물론 서버가 에러처리 잘하고 요청을 값넘기고 요청을 빠르게 닫는다면 정말 좋은 방식이긴 합니다.

문제는 서버 지연속도에 따라 클라이언트 쪽도 덩달아 얼어버리는 상황이 발생될 수 있습니다.

무슨뜻이냐면, a 라는 브라우저가 동기 XHR로 서버에 요청했을때, 서버가 값을 주고 요청을 닫기 전까지는 클라이언트는 그 어떤 js도 실행시킬 수 없습니다. 서버가 응답을 안해서 아직 finished상태가 되지 않았고 js 인터프리터는 구문을 순차적으로 실행하기 때문에 작업이 완료되지 않으면 새로운 작업을 시작할 수 없습니다. 그래서 비동기작업이 존재하는거구요.

 

그럼,

Good night :)

comment menu
2019.08.06. 22:25

신고

"Hanam09님의 댓글"

이 댓글을 신고 하시겠습니까?

이니스프리 작성자 → Hanam09
profile image

옙 잘 알겠습니다! 번번이 많이 배워서 감사합니다 ^^

당장 불편하게 느껴지더라도 depreciated 된 것은 나름대로의 이유가 있겠죠.

 

CSS & 자바스크립트 애니메이션이 제대로 작동하게 하려면

결국 ajax로 한꺼번에 파일들을 넘기고 PHP에서 cURL을 반복문으로 돌리는 방향으로 새로 짜는 것이 가장 바람직하겠네요~

멀티파일 업로드를 지원하지 않는 API를 클라이언트 단에서는 멀티파일을 선택하는 방식으로 작동하게 하는 것을

제가 처음 경험하다보니 시행착오가 꽤 있었네요 ㅠㅠ

 

그럼 오늘 밤에 태풍이 온다는데 비 조심하시고 굿밤 되세요!!

덕분에 이것저것 많이 배워서 다시 한 번 감사드립니다 :)

comment menu
2019.08.07. 00:30

신고

"이니스프리님의 댓글"

이 댓글을 신고 하시겠습니까?

권한이 없습니다.
번호 제목 글쓴이 날짜 조회 수
공지 시스템 점검 작업 완료 안내 10 마스터 24.09.05.16:25 2189
공지 [중요] 호스팅 만료와 관련하여 일부 수칙이 변경됩니다. 4 마스터 23.01.14.02:23 9045
공지 [필독] 질문하는 방법 17 마스터 18.02.23.03:09 4875
26 포인트 정리후 문제 발생.. 4 image 워시퍼 16.10.26.23:21 425
25 서비스 구매 후... 2 image title: 은메달도다 16.10.18.19:23 357
24 도메인 접속문제 해결? 1 RonnieJ 16.10.18.06:44 330
23 그누보드4 동영상 강좌는 없갯죠? 1 핫슈 16.10.17.23:28 361
22 IIS에 워드프레스 설치해서 쓰고 있는데 응답 속도가 너무 안 나옵니다. 6 file title: 금메달 (30일)동방개념지국 16.10.17.20:28 628
21 [스터디포어스] 호스팅사용자 제한, XE 설치 | 입문 도와드립니다. 3 title: 황금 서버 (30일)어코 16.10.17.19:35 492
20 그누보드 로고? 등록.. 5 title: 맛스타의 자물쇠에듀 16.10.16.17:51 537
19 xe를 설치할려고 하는데 도와주실 수 있으시나요? 8 image ryuko 16.10.15.16:19 522
18 SFU는 SSH를 지원하지 않나요? 2 Ursus 16.10.15.11:39 310
17 회원가입 이 외안되는거애요? 5 핫슈 16.10.14.19:01 290
16 동영상 스트리밍을 해주는 모듈설치...? 8 비빅 16.10.12.13:13 456
15 매번 마스터님께 질문만 드리기 그래서 여기다가 올려 봅니다...(동영상 스트리밍 서버) 2 비빅 16.10.11.10:07 356
14 호스팅 서비스 업그레이드 2 Wisdomhands 16.10.11.00:26 424
13 웹사이트 제작 13 Wisdomhands 16.10.10.23:55 658
12 Cloudflare의 인증서 등록 3 우마루 16.10.08.18:06 483
11 ssh 지원이 안되나요? 1 하마구리 16.10.08.15:08 297
10 미디어위키 설치를 하는데 여기서 멈춰버립니다 8 image ryuko 16.10.08.10:48 262
9 리눅스를 씁니다. 그런데말입니다.. 문제가.. 14 title: 황금 서버 (30일)하루살이 16.09.30.22:50 515
8 숨겨진 파일을 삭제하는 방법은 어떻게 해야하나요? 2 image 워시퍼 16.09.14.09:21 611
7 파일질라로 연결하니까 보안되지 않은 서버입니다. TLS를 통한 FTP를 지원하지 않습니다. 이렇게떠요 해결방안좀 1 마카오 16.09.11.00:57 3726