【问题标题】:AngularJS: How to avoid anonymous promise handlersAngularJS:如何避免匿名承诺处理程序
【发布时间】:2014-11-25 20:55:30
【问题描述】:

最近和我的客户,我们选择关注John Papa's AngularJS Style Guide*。

我目前正在检查当前的代码库,以确保没有留下任何匿名函数。但是,我遇到了一些承诺处理程序的情况,这些处理程序需要的参数不是由承诺的响应/拒绝设置,而是由另一个函数或参数设置。我曾尝试在回调中传递这些参数,但失败了。

function testPromise() {
  setPromiseAsPending();

  var timestamp = new Date().toString();

  firstModel.callPromise()
  // option 1: use of anonymous functions. works, but not the aim.
    // .then(
    //   function () {
    //     onPromiseResolved(timestamp);
    //   },
    //   function () {
    //     onPromiseRejected(timestamp);
    //   }
    // )['finally'](setPromiseAsCompleted);

  // option 2: naming functions in context. works, but less than ideal in our context.
    .then(
      function onPromiseResolved() {
        secondModel.logPromiseResults('this promise has been resolved on ' + timestamp);
      },
      function onPromiseRejected() {
        secondModel.logPromiseResults('this promise has been rejected on ' + timestamp);
      }
    )['finally'](setPromiseAsCompleted);

  // option 3: passing functions as variables. not good: doesn't work, missing the parameter.
    // .then(
    //   onPromiseResolved,
    //   onPromiseRejected
    // )['finally'](setPromiseAsCompleted);

  // option 4: calling functions with parameters. not good: both functions called.
    // .then(
    //   onPromiseResolved(timestamp),
    //   onPromiseRejected(timestamp)
    // )['finally'](setPromiseAsCompleted);

  // option 5: how do i pass the parameter to only be used when the function is called?

这里的目标是确保函数内没有声明函数,以便每个函数在同一级别命名和声明。我们的目标是减少函数的长度,尤其是让它们更易于测试。

请参阅上面的代码摘录,如果您有任何建议,请告诉我。请记住,这不是我们使用的代码,而是模拟函数工作方式的最小原型。

如果对您有帮助,也请参阅 the code in github。提前感谢您的帮助。

* 不要就样式指南进行宗教辩论,这不是本问题的主题。

【问题讨论】:

  • 我正在查看链接的样式指南,但我没有看到关于在同一级别声明函数并将它们全部命名的意义。命名你的内联函数是一件好事,但不应该不加思索地应用。纯粹的"partials" 是一个很好的例子,说明了的名称。
  • 该风格指南本身在这里使用匿名处理程序来处理承诺:github.com/johnpapa/angularjs-styleguide/blob/master/…。我不确定您要在这里完成什么,但样式指南似乎可以使用选项 1。
  • @hon2a:命名所有函数不仅是一件好事,而且当你有一个庞大的代码库要调试和大约 20 个开发人员时,这是必要的。我可能承认内联部分可能是必要的,但不能避免命名。
  • @BenjaminGruenbaumL 我同意风格指南并不能解决所有情况,但作为一个团队,这就是我们的目标。正如我对 hon2a 所提到的,我可能确实不得不承认在函数/类级别声明所有函数的部分。
  • @user4291649 命名函数的原因是在调试时有可理解的调用堆栈。 命名仅提供闭包且不执行自己的代码的函数同样重要。

标签: javascript angularjs promise anonymous-function angular-promise


【解决方案1】:

你可以使用Function.prototype.bind:

.then(
   onPromiseResolved.bind(null, timestamp),
   onPromiseRejected.bind(null, timestamp)
)['finally'](setPromiseAsCompleted);

然后您的函数将被调用,就像您在选项 1 中执行 onPromiseResolved(timestamp) 一样。

更多信息请参见the docs

【讨论】:

  • 我不知道这一点,我会调查一下,看看它是否能满足我们的需求,或者它是否是技术主管甚至为我们接受的东西。谢谢。
【解决方案2】:

你不要传递这个参数。您只需在函数定义中声明它。

要么使用“外部”函数声明

function onPromiseResolved(timestamp) {
    secondModel.logPromiseResults('this promise has been resolved with ' + timestamp);
}
function onPromiseRejected(err) {
    secondModel.logPromiseResults('this promise has been rejected with ' + err);
}

….then(onPromiseResolved, onPromiseRejected)

或命名函数表达式:

.then(function onPromiseResolved(timestamp) {
    secondModel.logPromiseResults('this promise has been resolved with ' + timestamp);
}, function onPromiseRejected(err) {
    secondModel.logPromiseResults('this promise has been rejected with ' + err);
})

这里的目标是确保一个函数内没有函数声明,以便每个函数在同一级别命名和声明

那是徒劳的。有时,您只需要 闭包(因为您不希望所有变量都是静态全局变量)。当然,您仍然可以将它们移出并显式传递闭包变量作为参数:

function makeOnPromiseResolvedHandler(closurevars) {
    return function onPromiseResolved(timestamp) {
        secondModel.logPromiseResults('this promise has been resolved with ' + timestamp);
        // use closurevars in here
    };
}

….then(makeOnPromiseResolvedHandler(…), …)

【讨论】:

  • 在您的回答的第二部分中,您将进入 OP 想要避免的“宗教辩论”:P 实际上,当您遵循指南时,您 don't get globals because of IIFE
  • @Bergi:我同意你的第一个例子,如果承诺响应将包含必要的信息,但是正如我解释的那样“我遇到了一些承诺处理程序需要参数而不是由响应设置的情况/rejection of the promise [...]” 更准确地说,我们称之为 webservice(UI 不可知),var 是根据情况的重定向 URL。我可能确实不得不使用您提到的命名函数表达式,因为命名更重要。
  • @m01:感谢您提出这个论点,我们确实与 IIFE 合作。
  • @m01:嗯,global 可能是错误的词 - 我们称它们为 static 变量。但是如果你的对象不是单例,你会想要避免它们。当您有闭包并希望将其中的功能移动到顶层时,您需要将所有闭包参数作为参数传递 - 并使用部分应用程序来制作回调函数。这可以使用闭包(如我的makeHandler sn-p)或使用.bind(如您的答案)来完成。
  • @user4291649:你说得对,我最初的回答(第一部分)并没有关注你的实际问题。
猜你喜欢
  • 1970-01-01
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 2023-03-26
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多