我正在使用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>
这是我想要做的:
我希望这是有道理的。我创建了一个如下所示的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知识来自己构建这个。所有的帮助表示赞赏。
答案 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,无论如何解析都是唯一的。)
最后一个警告。获取大量用户,然后获取大量图像,然后大量保存可能很容易超时。您可能需要在小批量用户中运行此操作以避免超时。