Javascript Meteor CollectionFS:确保在显示之前已上载图像

Javascript Meteor CollectionFS:确保在显示之前已上载图像,javascript,file-upload,meteor,amazon-s3,Javascript,File Upload,Meteor,Amazon S3,我正在使用带有S3适配器的软件包,我已经研究了一些不同的解决方案,但无法使其正常工作 问题:即使文件/图像已成功上载到S3,但在安全显示图像之前会触发成功上载的回调。这有时会导致显示损坏的图像 我发现了fileObj.once(“upload”,function(){})回调,但似乎“upload”基本上意味着将图像发送到服务器。到那时,S3上传不会发生。我发现的一个临时解决办法是只设置3-4秒的setTimeout,但这并不可靠 这是我的上传代码: FS.Utility.eachFile(ev

我正在使用带有S3适配器的软件包,我已经研究了一些不同的解决方案,但无法使其正常工作

问题:即使文件/图像已成功上载到S3,但在安全显示图像之前会触发成功上载的回调。这有时会导致显示损坏的图像

我发现了
fileObj.once(“upload”,function(){})
回调,但似乎“upload”基本上意味着将图像发送到服务器。到那时,S3上传不会发生。我发现的一个临时解决办法是只设置3-4秒的
setTimeout
,但这并不可靠

这是我的上传代码:

FS.Utility.eachFile(event, function(file) {
    Session.set('profilePhotoUploaded', false);
    var newFile = new FS.File(file);
    newFile.metadata = {owner: Meteor.userId()};    

    ProfileImages.insert(newFile, function (err, fileObj) {
      if (err){
         console.log("error! - " + err);
      } else {
         // handle success depending what you need to do

        var userId = Meteor.userId();

        // This does NOT run when image is stored in S3. I think it runs when the image reached the app server.
        fileObj.once("uploaded", function () {

            // timeout of 3 seconds to make sure image is ready to be displayed 
            // --- This is not a good solution and it image does is not always ready
            setTimeout(function(){ 
                var uploadedImage = {
                  "profile.image.url": "/cfs/files/profileImages/" + fileObj._id
                };
                Meteor.users.update(userId, {$set: uploadedImage});

                Session.set('profilePhotoUploaded', true);
            }, 3000);  

            console.log("Done uploading!");
        });
     }
   });
});

是否有不同的回调来检查映像是否实际存储在S3中?我尝试了
fileObj.once(“存储”,function(){})
,但这不起作用。

问题是,当原始图像保存在服务器上时,
存储的
钩子将启动,因此如果您创建多个副本(缩略图),此钩子将在存储缩略图之前启动。通过检查storeName参数,可以检查存储了哪个版本的缩略图。在服务器端文件中,定义
ProfileImages
集合的地方添加以下代码,将
'profilePhotoLarge'
替换为分配给
FS.Store.S3
存储的名称:

ProfileImages.on('stored', Meteor.bindEnvironment(function(fileObj, storeName) {
    if (storeName === 'profilePhotoLarge') {
        Meteor.users.update({_id: fileObj.metadata.owner}, {
            $set: {
                'profile.image.url': 'https://your AWS region domain/your bucket name/your folder path/' + fileObj._id + '-' +fileObj.name()
            }
        });
    }
}, function() { console.log('Failed to bind environment'); }));

对于个人资料照片,我创建了一个S3存储桶,并设置了允许任何人读取文件的权限,因此我将图像的URL存储在S3上,这在您的情况下可能不正确。由于用户对象在客户端是被动的,因此此更新将导致配置文件照片自动更新。

我发现
fileObj.hasStored(“profileImages”)
精确指定图像存储在S3上的时间。因此,在开始上传过程后,我只需每隔1秒启动一个计时器,检查它是否保存。这可能不是最好的解决方案,但这对我来说是有效的

FS.Utility.eachFile(event, function(file) {
    Session.set('profilePhotoUploaded', false);
    var newFile = new FS.File(file);
    newFile.metadata = {owner: Meteor.userId()};    // TODO: check in deny that id is of the same user

    ProfileImages.insert(newFile, function (err, fileObj) {
      if (err){
         console.log("error! - " + err);
      } else {
         // handle success depending what you need to do

        var userId = Meteor.userId();

        // Timer every 1 second
        var intervalHandle = Meteor.setInterval(function () {
                                    console.log("Inside interval");
                                    if (fileObj.hasStored("profileImages")) {
                                        // File has been uploaded and stored. Can safely display it on the page. 
                                        var uploadedImage = {
                                          "profile.image.url": "/cfs/files/profileImages/" + fileObj._id
                                        };
                                        Meteor.users.update(userId, {$set: uploadedImage});

                                        Session.set('profilePhotoUploaded', true);

                                        // file has stored, close out interval
                                        Meteor.clearInterval(intervalHandle);
                                    }
                                }, 1000);
     }
   });
});

事实上,我认为这真的会起作用。但事实并非如此。我想原因已经提到了,服务器上集合上的“存储”事件现在应该可以正常工作了。现在,您还可以在服务器上执行fileObj.on(“存储”,func),在客户端执行fileObj.on(“上载”,func)。最终,我们计划在客户机上为集合和FileObj发出“存储”的消息,但这更为棘手,而且尚未实现。因此,我正在尝试在客户机上获得一个“存储”回调。我猜这会在服务器端起作用。我想我已经找到了一个解决办法,尽管使用了计时器。很糟糕,客户端还没有回调来告诉应用程序文件已经安全存储,但这段代码现在必须完成。谢谢