[英]Synchronous Javascript Function with Promise doesnt work properly
我有以下功能,希望将其同步处理,但是以某种方式无法正常工作。
function upload_to_aws(data) {
return new Promise(function(resolve, reject) {
loan_application_id = $('#loan_application_id').val();
var s3BucketName = data.bucket_name;
var s3RegionName = data.region;
AWS.config.update({accessKeyId: data.key, secretAccessKey: data.secret_key, region: s3RegionName});
var s3 = new AWS.S3({params: {Bucket: s3BucketName, Region: s3RegionName}});
aws_url= []
$('.attached_image').each(function() {
if($(this).attr('src') != "/assets/upload_bg.png" && $(this).attr('src') != '' ) {
var timestamp = (new Date()).getTime();
var randomInteger = Math.floor((Math.random() * 1000000) + 1);
filename = 'self_evaluation_images/'+ loan_application_id + '_self_eval_ic_' + timestamp + '.png';
var u = $(this).attr('src').split(',')[1],
binary = atob(u),
array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
var typedArray = new Uint8Array(array);
s3_upload(s3, filename, typedArray).then(function(url_aws) {
aws_url.push(url_aws);
console.log(aws_url)
console.log(aws_url.length)
})
}
})
resolve(aws_url);
})
}
function s3_upload(s3, filename, typedArray) {
return new Promise(function(resolve, reject) {
s3.putObject({Key: filename, ContentType: 'image/png', Body: typedArray.buffer, ContentEncoding: 'base64', ACL: 'public-read'},
function(err, data) {
if (data !== null) {
url_aws = s3.endpoint.href + filename;
resolve(url_aws)
}
else {
reject(err);
}
});
})
}
调用此函数时,它将调用upload_to_aws
函数,我希望在该函数中执行所有操作,然后将其返回给我aws_uploaded url数组。
$.when(upload_to_aws(data.data)).then(function(aws_uploaded_url) {
console.log(aws_uploaded_url);
})
但是目前基本上发生的是,在将图像上传到s3的过程中,甚至在将图像上传到s3之前,它也被称为resolve(aws_url)
,因此这console.log(aws_uploaded_url)
打印为空数组[]
因为该功能尚未完全执行。
还有其他方法可以处理javascript中的回调和同步函数吗?
主要的问题是代码不会等待s3_update
返回的s3_update
得以解决并填充aws_url
数组,然后再使用该数组解决upload_to_aws
返回的promise(仍然为空)。
到目前为止,这是如何从异步调用返回响应的一个常见问题。 ,但用s3.putObject
方法代替AJAX调用。
您还想等待多个(零个或多个promise),因为请求数由数据决定。 等待多个承诺完成涉及Promise.all
的使用。
Promise.all
调用的实现值是作为参数提供的promise的实现值的数组,按照提供的参数顺序。 换句话说,实现的值是aws_url
使用的aws_url
数组。
一种(未经测试的)尝试方法,只需稍作修改即可声明所有变量并简化s3_upload
可以是:
function upload_to_aws(data) {
var loan_application_id = $('#loan_application_id').val();
var s3BucketName = data.bucket_name;
var s3RegionName = data.region;
AWS.config.update({accessKeyId: data.key, secretAccessKey: data.secret_key, region: s3RegionName});
var s3 = new AWS.S3({params: {Bucket: s3BucketName, Region: s3RegionName}});
var urlPromises = [];
$('.attached_image').each(function() {
if($(this).attr('src') != "/assets/upload_bg.png" && $(this).attr('src') != '' ) {
var timestamp = (new Date()).getTime();
var randomInteger = Math.floor((Math.random() * 1000000) + 1);
var filename = 'self_evaluation_images/'+ loan_application_id + '_self_eval_ic_' + timestamp + '.png';
var u = $(this).attr('src').split(',')[1];
var binary = atob(u);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
var typedArray = new Uint8Array(array);
urlPromises.push( s3_upload(s3, filename, typedArray))
}
});
return Promise.all( urlPromises);
}
function s3_upload(s3, filename, typedArray) { // promisify a call back
return new Promise(function(resolve, reject) {
s3.putObject(
{Key: filename, ContentType: 'image/png', Body: typedArray.buffer, ContentEncoding: 'base64', ACL: 'public-read'},
function(err, data) { err ? reject(err) : resolve( data);}
);
});
}
(如果任何声明的变量应该是全局变量,则删除它们前面的var
)。
调用upload_to_aws
返回的承诺应使用零个或多个上载网址的数组来实现:
$.when(upload_to_aws(data.data)).then(function(aws_uploaded_urls {
console.log(aws_uploaded_urls);
})
在版本3之前,jQuery未实现符合Aplus承诺规范或更高版本ECMAScript 6版本标准的承诺 。 较旧版本的JQuery完全无法将ES6承诺识别为承诺,并且无法等待它们被兑现。
检查您使用的是使用本机Promises的代码的JQuery 3还是更高版本。 如果需要支持IE浏览器,则还需要包含支持Promise.all
ES6样式承诺的Promise.all
。
如果您需要支持JQuery 3不再支持的浏览器,请考虑完全删除Promise用法,例如,围绕Deferred对象的使用来重构代码(超出此答案的范围)。 这也将消除缺少本地Promise支持的较旧浏览器中的polyfill的需求。
如果.when
方法在ES6 Promise使用方面出现问题,请考虑使用纯JavaScript调用代码:
upload_to_aws(data.data) .then(function(aws_uploaded_urls) { console.log(aws_uploaded_urls); }) .catch( function( err) { console.log( "upload_to_aws failed: ", err); }
因为每个迭代运行的都是异步的,所以您需要使用Promise.all
,将每个迭代映射到Promise
并在所有迭代的Promise
最终解决upload_to_aws
返回的Promise
:
function upload_to_aws(data) {
loan_application_id = $('#loan_application_id').val();
var s3BucketName = data.bucket_name;
var s3RegionName = data.region;
AWS.config.update({accessKeyId: data.key, secretAccessKey: data.secret_key, region: s3RegionName});
var s3 = new AWS.S3({params: {Bucket: s3BucketName, Region: s3RegionName}});
return Promise.all(
[...document.querySelectorAll('.attached_image')]
.map(image => new Promise((resolve, reject) => {
const { src } = image;
if(src != "/assets/upload_bg.png" && src != '' ) {
var timestamp = (new Date()).getTime();
var randomInteger = Math.floor((Math.random() * 1000000) + 1);
filename = 'self_evaluation_images/'+ loan_application_id + '_self_eval_ic_' + timestamp + '.png';
var u = src.split(',')[1],
binary = atob(u),
array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
var typedArray = new Uint8Array(array);
s3_upload(s3, filename, typedArray).then(resolve, reject);
}
}))
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.