将基于 Promise 的方法转换为回调

我是 js 新手。我已经阅读了许多关于异步性的先前堆栈溢出帖子,但仍然不明白下面的问题。


我有以下代码将图像文件上传到 S3 存储桶。代码需要实现的关键是让父级中的 image1 变量将信息存储在子函数中 s3.upload 调用的数据变量中。


我使用以下承诺的代码可以正常工作。我的理解是,同样的事情可以只使用回调来完成,我一直试图用回调重写下面的代码,只是作为一个学习练习,但它没有奏效。我将如何更改此代码以使用回调而不是承诺来做同样的事情?


父函数:


try {

      image1 = await uploadToAWSBucket(file);

}

catch (error) {

      return next(error);

}

孩子:


const uploadToAWSBucket = async (fileObject) => {

  let randomFileName = shortid.generate();

  const AWSUploadObject = {

    Bucket: BUCKET_NAME,

    Key: randomFileName,

    Body: fileObject.buffer,

    ContentType: fileObject.mimetype,

  };


  return new Promise((resolve, reject) => {

    s3.upload(AWSUploadObject, (err, data) => {

      if (err) {

        return reject(err);

      }

      return resolve(data);

    });

  });   

};


慕码人2483693
浏览 121回答 4
4回答

翻翻过去那场雪

首先,您需要为异步函数添加一个回调参数,删除 async 关键字const uploadToAWSBucket = (fileObject, callback) => {接下来,您需要以回调方式处理 s3 响应,将 Promise 替换为回调使用。s3.upload(AWSUploadObject, (err, data) => {  if (err) {    callback(err);    return;  }  callback(null, data);});或者你甚至可以将其简化为s3.upload(AWSUploadObject, callback)您还需要将您的使用更新为回调方式uploadToAWSBucket(file, (error, image1) => {  if (error) {    next(error);    return;  }  // your success code here});最终结果是const uploadToAWSBucket = (fileObject, callback) => {  let randomFileName = shortid.generate();  const AWSUploadObject = {    Bucket: BUCKET_NAME,    Key: randomFileName,    Body: fileObject.buffer,    ContentType: fileObject.mimetype,  };  s3.upload(AWSUploadObject, callback);};而已。我希望这个解释能帮助你理解如何使用回调。

12345678_0001

如果我的理解是正确的,你要image1在catchblock之后使用。在这种情况下,我想,您将使用image1. 可以按如下方式完成,其中一些片段来自此答案:const uploadToAWSBucket = (fileObject, callback) => { ... }; // described in the linked answeruploadToAWSBucket(file, function callback(error, image1) {    if(error) { return next(error); }  someOtherFunction(image1, next); // "next" is passed as callback, with the assumption that nothing else needed to be called after that.  });如果你想用 的结果调用另外 2 个函数someOtherFunction,可以这样做:uploadToAWSBucket(file, function callback(error, image1) {    if(error) { return next(error); }  someOtherFunction(image1, function someOtherFunctionCb(error, someOtherFunctionResult) {    if(error) { return next(error); }    someOtherFunction2(someOtherFunctionResult, function someOtherFunction2Cb(error, someOtherFunction2Result) {      if(error) { return next(error); }      someOtherFunction3(someOtherFunction2Result, function someOtherFunction3Cb(error, someOtherFunction3Result) {        if(error) { return next(error); }        next(null, someOtherFunction3Result);      });    });   }); });基本上,如果您使用回调,则不能拥有局部全局变量。我将尝试解释一个问题的情况。let image1 = null;uploadToAWSBucket(file, function uploadToAWSBucketCallback(error, _image1) {    if(error) { return next(error); }  image1 = _image1;});someOtherFunction(image1, function someOtherFunctionCb(error, someOtherFunctionResult) {  if(error) { return next(error); }    ...}); 在上面的代码片段中,someOtherFunction将在uploadToAWSBucketCallback执行之前调用。这意味着,image1没有分配给_image1。现在,您知道调用image1when的值是多少someOtherFunction。第二个片段显示了如何通过将后续调用嵌套在回调中来将一个异步函数的结果传递给另一个。这使许多人的代码可读性降低。有类似的库async,这有助于使事情变得更容易和可读。第二个片段可以用async库的waterfall函数重写,如下所示:async.waterfall([    function uploadToAWSBucketStep(callback) {        uploadToAWSBucket(file, callback);    },    function someOtherFunctionStep(image1, callback) {        someOtherFunction(image1, callback);    },    function someOtherFunction2Step(someOtherFunctionResult, callback) {        someOtherFunction2(someOtherFunctionResult, callback);    },    function someOtherFunction3Step(someOtherFunction2Result, callback) {        someOtherFunction3(someOtherFunction2Result, callback);    }], function lastStep(error, someOtherFunction3Result) {    if(error) { return next(error); };    next(null, someOtherFunction3Result);});

慕田峪9158850

在阅读了每个人的回复后,我想出了以下我认为可行的方法,基本上是@Pavlo Zhukov 建议的。(请注意,函数名称与我之前的帖子略有不同。)来自父函数的代码:let image1;uploadToAWSBucketCallbackStyle(file, (err, data) => {  if (err) {    return next(err);  }  image1 = data;  // Do stuff with image1 here or make additional function  // calls using image1.});子函数:const uploadToAWSBucketCallbackStyle = (fileObject, callback) => {  let randomFileName = shortid.generate();  const AWSUploadObject = {    Bucket: BUCKET_NAME,    Key: randomFileName,    Body: fileObject.buffer,    ContentType: fileObject.mimetype,  };  s3.upload(AWSUploadObject, callback);}

烙印99

Promisifcation 基于回调的函数是很好理解和有据可查的。我从未见过关于“去承诺”的讨论,但这很简单。从您开始uploadToAWSBucket()并假设您希望您的回调是“nodeback”样式(签名(err, data)),那么您可以编写:const uploadToAWSBucketNodeback = (fileObject, nodeback) => {    uploadToAWSBucket(fileObject) // call the promise-returning "async" version.    .then(data => { // success path        nodeback(null, data);    })    .catch(nodeback); // error path};或者你可以写一个通用的去承诺...const depromisify = (asyncFunction) => {    return function(...params) {        let nodeback = params.pop(); // strip nodeback off the end of params        asyncFunction(...params)        .then(data => { // success path            nodeback(null, data);        })        .catch(nodeback); // error path    }};... 然后const uploadToAWSBucketNodeback = depromisify(uploadToAWSBucket);任何一种方法都允许您编写:uploadToAWSBucketNodeback(fileObject, function(err, data)) {    if(err) {        // handle error    } else {        // handle data    }}笔记我们只需要知道原始的 asyncFunction 是 thenable/catchable 即可。原始的 asyncFunction 对 depromisified 函数完全不透明。我们不需要了解原始 asyncFunction 的内部工作原理。因此,AWSUploadObject不需要复制的组成......它仍然由uploadToAWSBucket().
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript