【问题标题】:Nesting warning - avoid nesting problems嵌套警告 - 避免嵌套问题
【发布时间】:2019-07-08 21:00:22
【问题描述】:

我已尝试解决嵌套问题,但我使用的任何方法都不起作用,甚至 Google Cloud Functions - warning Avoid nesting promises promise/no-nesting

我该如何重构这个方法?下面是代码。

exports.payout = functions.https.onRequest((request, response) => {
var uid = "nYIAHSYimJMHbMkXqDt9PQ0U3Nf2";

getPayoutsPending(uid).then((array) => {
    getPayoutsAmount(array).then((value) => { **// avoid nesting promises**  
        var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);

        const sender_batch_id = Math.random().toString(36).substring(9);
        const sync_mode = 'false';
        const payReq = JSON.stringify({
            sender_batch_header: {
                sender_batch_id: sender_batch_id,
                email_subject: "You have a payment"
            },
            items: [
                {
                    recipient_type: "EMAIL", 
                    amount: {
                        value: valueTrunc,
                        currency: "CAD"
                    },
                    receiver: "me@gmail.com",
                    note: "Thank you.",
                    sender_item_id: "Payment"
                }
            ]
        });

        paypal.payout.create(payReq, sync_mode, (error, payout) => {
            if (error) {
                console.warn(error.response);
                response.status('500').end();
                throw error;
            } else {
                console.info("payout created");
                console.info(payout);

                **// avoid nesting problems** 
                updatePaymentsPending(uid, sender_batch_id).then(() => {
                    response.status('200').end();
                    return;
                }).catch((error) => {
                    return console.error(error);
                })
            }
        });
        return null;
    }).catch((error) => {
        return console.error(error);
    })
    return null;
}).catch((error) => {
    return console.error(error);
})

});

标记为//避免嵌套承诺的行是问题所在。

编辑 - 答案结果

第 111:20 行内容如下: return paypal.payout.create(payReq, sync_mode, (error, payout) => {

第 120:21 行内容如下: }).then(() => {

编辑#2

将代码更改为@imjared 提供的代码后,我收到以下错误:

ReferenceError: sender_batch_id is not defined
at exports.payout.functions.https.onRequest (/user_code/index.js:136:40)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /var/tmp/worker/worker.js:689:7
at /var/tmp/worker/worker.js:673:9
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)

然后:

Function execution took 1327 ms, finished with status: 'crash'

然后:

ReferenceError: paymentRequest is not defined
at Promise (/user_code/index.js:111:17)
at buildPaymentRequest (/user_code/index.js:90:14)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)

编辑 #3 - 来自 detenson 帖子的回复

我的代码:

exports.payout = functions.https.onRequest((request, response) => {
return getPayoutsPending(request.body.uid)
    .then(array => getPayoutsAmount(array))
    .then(value => {
        var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);
        const sender_batch_id = Math.random().toString(36).substring(9);
        const sync_mode = 'false';
        const payReq = JSON.stringify({
            sender_batch_header: {
                sender_batch_id: sender_batch_id,
                email_subject: "You have a payment"
            },
            items: [
                {
                    recipient_type: "EMAIL",
                    amount: {
                        value: valueTrunc,
                        currency: "CAD"
                    },
                    receiver: request.body.email,
                    note: "Thank you.",
                    sender_item_id: "Payment"
                }
            ]
        });

        return paypal.payout.create(payReq, sync_mode, (error, payout) => {
            if (error) {
                console.warn(error.response);
                response.status('500').end();
                throw error;
            }
            console.info("payout created");
            console.info(payout);
            return updatePaymentsPending(request.body.uid, sender_batch_id)
        }).then(() => {
            response.status('200').end();
            return null;
        });
    })
    .catch(error => {
        console.error(error);
    });
});

应用程序执行时,函数日志显示如下:

TypeError: Cannot read property 'then' of undefined
at getPayoutsPending.then.then.value (/user_code/index.js:120:15)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)

然后:

    { batch_header: 
   { payout_batch_id: '*************',
     batch_status: 'PENDING',
     sender_batch_header: 
      { sender_batch_id: '************',
        email_subject: 'You have a payment' } },
  links: 
   [ { href: 'https://api.sandbox.paypal.com/v1/payments/payouts/*******',
       rel: 'self',
       method: 'GET',
       encType: 'application/json' } ],
  httpStatusCode: 201 }

然后:

uncaught exception

然后:

ReferenceError: uid is not defined
at paypal.payout.create (/user_code/index.js:119:46)
at IncomingMessage.<anonymous> (/user_code/node_modules/paypal-rest-sdk/lib/client.js:140:13)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickDomainCallback (internal/process/next_tick.js:128:9)

最后:

Function execution took 1517 ms, finished with status: 'crash'

编辑 #4 - 最终结果

执行应用程序后,函数的以下日志是:

【问题讨论】:

    标签: javascript firebase google-cloud-functions


    【解决方案1】:

    我会通过链接 promise 而不是嵌套它们来解决这个问题。当您从 then() 回调中返回一个值时,它会成为一个新的 Promise,然后可以再次使用。

    我没有测试过你的代码的这个修改版本,但我希望你能明白它的要点:

    exports.payout = functions.https.onRequest((request, response) => {
        var uid = "nYIAHSYimJMHbMkXqDt9PQ0U3Nf2";
    
        return getPayoutsPending(uid)
            .then(array => getPayoutsAmount(array))
            .then(value => {
                var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);
                const sender_batch_id = Math.random().toString(36).substring(9);
                const sync_mode = 'false';
                const payReq = JSON.stringify({
                    sender_batch_header: {
                        sender_batch_id: sender_batch_id,
                        email_subject: "You have a payment"
                    },
                    items: [
                        {
                            recipient_type: "EMAIL",
                            amount: {
                                value: valueTrunc,
                                currency: "CAD"
                            },
                            receiver: "me@gmail.com",
                            note: "Thank you.",
                            sender_item_id: "Payment"
                        }
                    ]
                });
    
                return paypal.payout.create(payReq, sync_mode, (error, payout) => {
                    if (error) {
                        console.warn(error.response);
                        response.status('500').end();
                        throw error;
                    }
                    console.info("payout created");
                    console.info(payout);
                    return updatePaymentsPending(uid, sender_batch_id)
                });
            }).then(() => {
                response.status('200').end();
                return null;
            }).catch(error => {
                console.error(error);
            });
    });
    

    我希望这会有所帮助。

    编辑:成功的案例缺少返回空值。我猜你的 linter 对此很挑剔。

    编辑:未嵌套最后一个then()

    【讨论】:

    • 感谢您的回复 - 我按照您的建议做了,并在显示结果的 EDIT 部分更新了我的问题。
    • 您的 linter 抱怨在 response.status('200').end(); 之后缺少 return null
    • 通过上述调整,它会删除除一个之外的所有警告:111:20 警告避免嵌套承诺承诺/不嵌套 - 这行就是它所说的 - return paypal.payout.create(payReq, sync_mode, (error, payout) => {
    • 好的,还有一个then 仍然嵌套,我会修复它。
    • 顺便说一句:练习非嵌套 promise 可能是个好主意。它使代码更易于阅读和推理,因为它看起来更具顺序性。
    【解决方案2】:

    也未经测试,但似乎基于您的 eslint 的目标是取消嵌套所有内容。这有点麻烦,但我想这是可行的。

    exports.payout = functions.https.onRequest((request, response) => {
      var uid = "nYIAHSYimJMHbMkXqDt9PQ0U3Nf2";
    
      // Returns paymentRequest
      const buildPaymentRequest = (value) => {
        return new Promise((resolve) => {
          var valueTrunc = parseFloat(Math.round(value * 100) / 100).toFixed(2);
    
          const sender_batch_id = Math.random().toString(36).substring(9);
          const sync_mode = 'false';
          const payReq = JSON.stringify({
            sender_batch_header: {
              sender_batch_id: sender_batch_id,
              email_subject: "You have a payment"
            },
            items: [{
              recipient_type: "EMAIL",
              amount: {
                value: valueTrunc,
                currency: "CAD"
              },
              receiver: "me@gmail.com",
              note: "Thank you.",
              sender_item_id: "Payment"
            }]
          });
          resolve(paymentRequest);
        });
      }
    
      // Returns payout
      const createPayout = (paymentRequest) => {
        return new Promise((resolve, reject) => {
          paypal
            .payout
            .create(payReq, sync_mode, (error, payout) => {
              if (error) {
                console.warn(error.response);
                reject(error);
              } else {
                console.info("payout created");
                resolve(payout);
              }
            });
        });
      };
    
      getPayoutsPending(uid)
        .then(getPayoutsAmount)
        .then(buildPaymentRequest)
        .then(createPayout)
        .then(updatePaymentsPending(uid, sender_batch_id))
        .then(() => {
          response.status('200').end();
          return;
        })
        .catch((err) => {
          console.log(err);
          response.status('500').end();
          return console.error(error);
        })
    });
    

    或者,在文件顶部添加// eslint-disable 可以解决您的问题;)

    【讨论】:

    • 您提供的代码消除了警告,但会导致其他问题。当我在 firebase 中查看函数中的日志时,出现错误...请参阅 EDIT #2
    猜你喜欢
    • 2019-05-22
    • 2019-03-04
    • 1970-01-01
    • 2011-02-16
    相关资源
    最近更新 更多