【问题标题】:Is there a JavaScript preprocessor that makes callbacks look nice?有没有让回调看起来不错的 JavaScript 预处理器?
【发布时间】:2013-02-11 08:47:05
【问题描述】:

像 jQuery 这样的 JavaScript 工具包都是关于回调函数的,而且这些回调通常是匿名定义的。示例:某些网页在表格中显示消息列表。要更新此表,它可能首先向服务器询问所有当前消息(作为 ID)的列表,然后检索未知消息 ID 的内容:

function fnUpdateMessages() {
   $.ajax({
      type: 'POST',
      data: { action: 'get_message_ids' },
      success: function(sData) {
         var aMessageIds = sData.split(/,/);
         var aUnknownIds = fnWhichIdsAreNotInTable(aMessageIds);
         $.ajax({
            type: 'POST',
            data: {
               action: 'get_message_contents',
               ids: aUnknownIds.join(',')
            },
            success: function(oData) {
               for (var id in oData.messages) {
                  fnInsertMessage(oData.messages[id]);
               }
            }
         );
      }
   );
}

你知道我要去哪里吗?这段代码很难看,因为在随后的 2 次 AJAX 调用之后缩进处于第 6 级。我当然可以在文件范围内将匿名函数拆分为单独的函数,但这通常会污染命名空间(除非通过将其包装在另一个匿名函数调用中进一步混乱)并且它打破了这些函数之间的牢固联系:回调应该真的不能自己用;它们就像原始 fnUpdateMessages 函数的第二和第三部分一样。

我更想要的是这样的:

function fnUpdateMessages() {
   $.ajax({
      type: 'POST',
      data: { action: 'get_message_ids' },
      success: continue(sData)
   });

   var aMessageIds = sData.split(/,/);
   var aUnknownIds = fnWhichIdsAreNotInTable(aMessageIds);
   $.ajax({
      type: 'POST',
      data: {
         action: 'get_message_contents',
         ids: aUnknownIds.join(',')
      },
      success: continue(oData)
   );

   for (var id in oData.messages) {
      fnInsertMessage(oData.messages[id]);
   }
}

这个 sn-p 引入了新的假设语法 continue(var1, var2, [...]),它定义了一个匿名回调函数,其主体是封闭函数范围内的所有内容。这使得这些回调函数看起来像同步代码。显然,这必须进行预处理,因为它不是标准的 JS。

在我考虑编写这样的预处理器之前,我想知道这样的东西是否已经存在?

附:如果你喜欢这个主意,请把它偷走。我现在买不起另一个项目。如果您可以找到一些工作代码,那么在评论中提供指向您的存储库的链接会很棒。

【问题讨论】:

  • nicolas.perriault.net/code/2013/…也许这篇文章能帮到你?
  • 为了不污染命名空间,您可以使用闭包使回调看起来像对象中的私有函数,并使用该对象的实例来完成工作......或者您可以使用 coffeescript 或 typescript 。 ..
  • @limelights:看起来很有趣,但乍一看,这对我没有帮助,因为我的动作本质上是不可并行的。

标签: javascript asynchronous preprocessor


【解决方案1】:

只有两种解决方案:

第一个非常糟糕:您必须使第一个 ajax 请求同步,但您的脚本将阻塞,直到结果可用。 这确实是一个糟糕的解决方案,您不应该使任何 ajax 请求同步。

第二个在 $.ajax 的延迟对象返回上使用 jQuery.pipe 函数(你必须使用 jquery > 1.5)。 您可以像这样使用管道链接回调(我使用内部函数使其更具可读性):

[编辑]:从 jquery 1.8 开始,您应该使用 deferred.then 而不是 deferred.pipe :

    function fnUpdateMessages() {
        var getMessages = function() {
            return $.ajax({
                type: 'POST',
                data: { action: 'get_message_ids' },
            });
        };

        var getContents = function(aUnknownIds) {
            return $.ajax({
                type: 'POST',
                data: {
                    action: 'get_message_contents',
                    ids: aUnknownIds.join(',')
                },
            });
        };

        var insertMessages = function(oData) {
            for (var id in oData.messages) {
                fnInsertMessage(oData.messages[id]);
            }
        };

        getMessages()
            .then(getContents)
            .done(insertMessages);
     }

【讨论】:

    【解决方案2】:

    您可以使用 jQuery 的 deferreds 来链接回调,而不是将它们包含在选项中。

    function fnUpdateMessages() {
       $.ajax({
          type: 'POST',
          data: { action: 'get_message_ids' }
       ).done(function(sData) {
          var aMessageIds = sData.split(/,/);
          var aUnknownIds = fnWhichIdsAreNotInTable(aMessageIds);
          $.ajax({
             type: 'POST',
             data: {
                action: 'get_message_contents',
                ids: aUnknownIds.join(',')
             }
          }).done(function(oData) {
             for (var id in oData.messages) {
                fnInsertMessage(oData.messages[id]);
             }
          });
       });
    }
    

    它并不完美,但它会为每个请求节省几级缩进。

    有关更多信息,请参阅$.ajax 的文档。

    【讨论】:

      【解决方案3】:

      是的,有。它被称为jwacs - JavaScript With Advanced Continuation Support。简单地说,您使用延续来暂停程序的执行。然后,您可以通过调用延续来恢复程序的执行。延续始终保留程序在创建时的状态。

      这有点像trampolining in JavaScript,但蹦床依赖于仅由 Mozilla 产品(Firefox 和 Rhino)支持的生成器。如果您对蹦床感兴趣,我编写了一个库来使异步编写变得可以忍受。它叫做Fiber,有点像协作Java线程。

      另一方面,jwacs 编译成普通的 JavaScript。因此它可以在任何平台上使用。不仅仅是火狐和犀牛。如果您想了解什么是延续,那么我建议您阅读以下 StackOverflow 问题和答案:

      问题:What's the difference between a continuation and a callback?

      答案:https://stackoverflow.com/a/14022348/783743

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-05
        • 2014-10-01
        • 1970-01-01
        • 2020-01-25
        • 1970-01-01
        • 1970-01-01
        • 2022-09-30
        相关资源
        最近更新 更多