2

Я пишу плагин для загрузки редактора WYSIWYG, который я использую в приложении Meteor (Meteor 1.2.1). Я использую Slingshot для загрузки файлов на Amazon S3. Мой плагин вставляет ссылку в редакторе в загруженный файл после загрузки файла. Пока ничего фантастического.Обработка синхронизированных нескольких загруженных файлов '

Для однофайловой загрузки это не проблема. В случае многофайловой загрузки все становится сложнее. Я бы хотел, чтобы после загрузки всех файлов я получал массив имен файлов и URLS и вставлял хороший HTML-список, содержащий все ссылки (меня не волнует точная последовательность файлов и ссылок).

Slingshot использует функцию асинхронной для загрузки файла:

uploader.send(document.getElementById('input').files[0], function (error, downloadUrl) { 
    if (error) { 
    // Log service detailed response. 
    console.error('Error uploading', uploader.xhr.response); 
    alert (error); 
    } else { 
    Meteor.users.update(Meteor.userId(), {$push: {"profile.files": downloadUrl}}); 
    } 
}); 

возвращая URL загруженного файла в функции обратного вызова. Чтобы собрать, например, 5 URL-адресов из 5 загруженных файлов, я думаю, что мне нужна функция async «send» от Slingshot, чтобы вести себя как функция синхронизации.

Надеюсь, я правильно понял, что Meteor.wrapAsync не будет работать, поскольку все делается на клиенте. Я заглянул в javascript Promise, но это довольно подавляющее. И это становится сложнее понять в контексте Метеор. Обещание выглядит многообещающим, но я не понимаю, какой пакет использовать.

Может кто-нибудь объяснить, как решить (клиентскую) работу с несколькими (одинаковыми) вызовами функции async в строке, собрать результаты и использовать их после завершения загрузки?

Цените это,

CsPR

ответ

2

async библиотека имеет метод mapSeries, который позволит вам сделать это. Это позволяет перебирать массив с (возможно) асинхронной функцией и возвращает массив всех результатов, когда конечная задача асинхронной завершена:

var files = [file1, file2, file3]; 

function iterator(file, callback) { 
    uploader.send(file, function(err, downloadUrl) { 
    if (err) callback(err); 
    else callback(null, downloadUrl); 
    }); 
} 

function done(err, results) { 
    // results is an array of URLs 
} 

async.mapSeries(files, iterator, done); 

Если вы не заботитесь о порядке в которые обрабатываются, вы можете использовать обычный метод async.map для параллельного выполнения задач.

+0

Работал как шарм! Благодарю. –

1

Что мешает вам просто перебор входных файлов, загружать их асинхронны и спрашивать у того, как мы закончили на каждый обратном вызов?

var inputs = document.getElementsByTagName('input'); 
var urls = []; 

for (var i = 0; i < inputs.length; i++) { 

    if (inputs[i].files == null) { continue; } 

    uploader.send(inputs[i].files[0], function (error, downloadUrl) { 

    if (error) { 

     console.error('Error uploading', uploader.xhr.response); 

    } else { 

     urls.push(downloadUrl); 

     if (urls.length > inputs.length - 1) 
     allFilesUploaded(); 
    } 
    }); 
} 

function allFilesUploaded() { 

    Meteor.users.update(Meteor.userId(), {$push: {"profile.files": urls}}); 
    console.log('All done!'); 

} 
+0

У меня нет сомнений в том, что это работает, и я проклинаю себя, что я упустил этот метод. Но мне понравился предыдущий ответ немного лучше. –

+0

@CasperKaandorp достаточно справедливо. Другой ответ рекомендует хорошую библиотеку. Я думаю, вы получите более полное представление о том, как иметь дело с асинхронным кодом из коробки в моем ответе, но это не обязательно означает, что он должен быть помечен как правильный. Вот за что голосование. :-) – shennan

Смежные вопросы