如何根据承诺制作异步功能

时间:2017-08-25 18:32:39

标签: javascript node.js es6-promise

问题是该功能不会等到地图完成后

我认为解决方案是Promise.all 但我不知道如何使用这个功能

exports.createProduct = (data) => {
  var imgS3arr = []; //array which we waiting for
  data.img.map((img, i) => {
    fetch.remote(img).then((base) => {
        var buf = Buffer.from(base[0], 'base64');

        var imgS3 = {
            Key: data.title + i, //TODO: add random
            Body: buf,
            ContentEncoding: 'base64',
            ContentType: 'image/jpeg'
        };

        s3Bucket.putObject(imgS3, function (err, data) {
            if (err) {
                console.log(err);
                console.log('Error uploading data: ', data);
            } else {
                var params = this.request.params;
                var region = this.request.httpRequest.region;
                imgS3arr.push('https://s3-' + region + '.amazonaws.com/' + params.Bucket + '/' + params.Key)
            }
        }
      );
    }).catch((reason) => { });
});

//next part of code must be executed when all items pushed to 'imgS3arr'

const product = new Product({
    title: data.title,
    img: imgS3arr,  //we waiting for this array
});
return product.save((function (err) {
    if (err) {
        console.log(err);
    } else {
        console.log('Added new! \n' + product);
    }
  }));
}

有人可以帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

您可以这样做:

// returns a promise that is resolved when everything is done
//    or rejected with the first error that occurs
exports.createProduct = (data) => {
    var imgS3arr = []; //array which we waiting for
    return Promise.all(data.img.map((img, i) => {
        return fetch.remote(img).then((base) => {
            var buf = Buffer.from(base[0], 'base64');

            var imgS3 = {
                Key: data.title + i, //TODO: add random
                Body: buf,
                ContentEncoding: 'base64',
                ContentType: 'image/jpeg'
            };

            return s3Bucket.putObject(imgS3).promise().then(function(data) {
                // given other changes here and unfamiliarity with this code
                // I'm unsure if `this` still has the right value in it here
                var params = this.request.params;
                var region = this.request.httpRequest.region;
                imgS3arr.push('https://s3-' + region + '.amazonaws.com/' + params.Bucket + '/' + params.Key)
            }).catch(function(err) {
                // log error, then rethrow to keep the promise rejected
                console.log(err);
                console.log('Error uploading data: ', data);
                throw err;
            });
        });
    })).then(function() {
            const product = new Product({
                title: data.title,
                img: imgS3arr, //we waiting for this array
            });
            // use database interface that uses promises, not plain callbacks
            return product.save(...);
        }
    });
}

所做更改的摘要和解释:

  1. data.img.map()内,返回一个承诺,以便.map()创建一系列承诺。
  2. 在该承诺数组上使用Promise.all()以了解它们何时完成。
  3. 切换到s3Bucket.putObject(imgS3).promise(),这样我们就可以使用promises而不是普通的回调。
  4. 记录后.catch()中的Rethrow错误,因此保证会被拒绝
  5. 将您要等待的代码放在Promise.all().then()处理程序中。
  6. product.save()切换到使用promises而不是普通回调的数据库接口,这样你就可以直接链接那个promise(由于我们甚至不知道它是什么数据库,所以要留给OP)。