繁体   English   中英

带Promise的同步Javascript函数无法正常工作

[英]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);
})


jQuery兼容性 (更新)

在版本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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM