如何使用Parse Cloud Code下载图像并将其保存在阵列中?

时间:2016-02-10 16:18:44

标签: javascript parse-platform cloud

我正在使用Parse.com作为iOS应用程序的后端服务,我有一个专栏将Facebook中的个人资料图片存储为数组中的URL。

像这样:

[
    "https://z-1-scontent.xx.fbcdn.net/hp...e=5737C2D1",
    "http://files.parsetfss.com/9b0a70...40906b-newProfilePic.png",
    "http://files.parsetfss.com/9b0a70...24dd6-newProfilePic.png"
]

这些网址有时会过期(由于Facebook规则)并且不包含图片。互联网的其他方面也不建议存储这样的个人资料图片。

所以我想做的是制作一个Parse Cloud Code Javascript,通过从URL下载图像并将它们保存为新列中的新数组中的Parse文件,将配置文件图片URL迁移到实际图像文件中。 / p>

这是我想要做的:

  • 在Parse
  • 中查询所有用户
  • 获取他们的个人资料图片网址
  • 从每个网址下载图片
  • 创建图像文件
  • 将图像添加到新阵列
  • 将该数组保存到用户

我希望这是有道理的。我创建了一个如下所示的Cloud Code函数:

Parse.Cloud.define(“migrateColumn”,function(request,response){

Parse.Cloud.useMasterKey();

var usersToSave = [];
var profileImages = [];

var userQuery = new Parse.Query("User");
userQuery.find().then(function(users) {

    for (var a = 0; a < users.length; a++) {
          var user = users[a];
          var profileURLs = user.get("profilePictures");

          for (var b = 0; b < profileURLs.length; b++) {
              var url = profileURLs[b];

              Parse.Cloud.httpRequest({
                    url: url
              }).then(function(httpResponse) {
                  var imageBuffer = httpResponse.buffer;
                  var base64 = imageBuffer.toString("base64");
                  var file = new Parse.File("userProfileImage.png", { base64: base64 });

                  profileImages.push(file);
              });
          }

      user.set("profileImages", ["profileImage" + (a + 1)]);
      usersToSave.push(user);
    }
}).then(function() {
    Parse.Object.saveAll(usersToSave, {
        success: function() {
            response.success("Success : " + profileImages);

        }, error: function(error) {
            response.error("An error occurred : " + error.message);
        }
    });
});

});

我知道httpRequest是异步完成的,我需要以某种方式实现Promise,等待所有图像完成下载。我没有足够的Javascript知识来自己构建这个。所有的帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

你走在正确的轨道上。如果您创建执行逻辑任务并返回承诺的函数,那么一切都会变得更简单。例如,一个函数如何获取单个url并返回单个PFFile ...

function fileFromUrl(url, name) {
    return Parse.Cloud.httpRequest({url: url}).then(function(httpResponse) {
        var imageBuffer = httpResponse.buffer;
        var base64 = imageBuffer.toString("base64");
        var file = new Parse.File(name, { base64: base64 });
        // edit - pretty sure file.save resolves to file, but just in case...
        return file.save().then(function() { return file; });
    }, function(error) {
        // can't fetch the image for some reason
        // ideas:
        return null; // and have your UI check for nulls in the user image array
        // or return cannedImage(); where this function returns a promise 
        // for a PFFile that already exists
    });
}

现在可以更容易地为一组网址编写一个...

var _ = require('underscore');
function function filesFromUrls(urls) {
    var promises = _.map(urls, function (url, index) {
        return fileFromUrl(url, ''+index);
    });
    return Parse.Promise.when(promises).then(function() {
        return _.toArray(arguments);
    });
}

现在为用户更容易做到这一点......

function convertUrlsToFilesForUser(user) {
    var profileURLs = user.get("profilePictures");
    return filesFromUrls(profileURLs).then(function(files) {
        // profileImages should be an array of PFFiles, not an array of arrays as you have it
        user.set("profileImages");
        return user.save();
    });
}

现在在云功能中很容易做到这一点......

var userQuery = new Parse.Query("User");
userQuery.find().then(function(users) {
    var promises = _.map(users, function(user) {
        return convertUrlsToFilesForUser(user);
    });
    return return Parse.Promise.when(promises);
}).then(function(result) {
    response.success(result);
}, function(error) {
    response.error(error);
});

警告:我没有测试此代码。这里所做的就是重构操作以简化和正确使用承诺。在这些操作中,我使用了您的代码,我也没有测试过。

我更改的一个设计元素是您似乎保存了一组数组profileImages,例如:[ [ PFFile, '0'], [ PFFile, '1'], ... 我把它改成了一系列PFFiles。我想你想要第二个元素就像一个文件名。我在PFFile的构造函数中添加了它所属的名称(文件的名称不重要,因为它只影响文件的半透明URL,无论如何解析都是唯一的。)

最后一个警告。获取大量用户,然后获取大量图像,然后大量保存可能很容易超时。您可能需要在小批量用户中运行此操作以避免超时。