1

私はapache、php、js/jqueryに基づいたWebアプリケーションを持っています。ドキュメントがロードされると、アプリケーションの1つのモジュールが初期化されます。このシーケンスは、いくつかのタスクを実行するinit()関数を呼び出します。特に、ajaxを介して2つのhtmlダイアログをフェッチし、それらを既存のページに挿入します。これらのダイアログへの参照は変数として保存されるため、スクリプト全体でjqueryセレクターを指定する必要はありませんが、代わりにこれらの変数を使用できます。フェッチされたダイアログ内の要素にハンドラーをバインドしようとしたときに変数が「未定義」である場合がほとんどないことを除いて、これは正常に機能します。それとは別に、ダイアログはアプリケーション全体で使用できるため、これは奇妙なことです。これは、ajax呼び出しが成功したことを示していますが、明らかに何らかの競合状態があります。バインドの試行後。

私の理解では、バインドはwhen()の.done()部分で行われ、ダイアログのajax取得がwhen()内で終了した後にのみ実行されるため、これは発生しないはずです。

どうやら私はここで基本的な何かが欠けています。誰かが私にヒントを得ましたか?

以下は、実際の実装からのコードの抜粋を引用しています。一部の部分として構文的に無効に見える場合がありますが、これは、ここでは関係のないコード部分が削除されたためです。短縮されていないコードは正常に機能します。

変数:

Shorty.Tracking.Dialog.List:{};
Shorty.Tracking.Dialog.Click:{};

初期化シーケンス:

$(window).load(function(){
  //...
  var dfd = new $.Deferred();
  $.when(
    // load layout of dialog to show the list of tracked clicks
    Shorty.Tracking.init()
  ).done(function(){
    // bind actions to basic buttons
    Shorty.Tracking.Dialog.List.find('#close').on('click',function(){
      // ...
    });
    // ...
  });
  // ...
})

短縮されたinit関数:

Shorty.Tracking.init:function(){
    // ...
    var dfd=new $.Deferred();
    // two dialogs are used by this plugin
    var dialogs={
      'list':  Shorty.Tracking.Dialog.List,
      'click': Shorty.Tracking.Dialog.Click
    };
    // load dialogs from server
    $.each(['list','click'],function(i,dialog){
      if (...){
        // ...
        dfd.resolve();
      }else{
        // load dialog layout via ajax and create a freshly populated dialog
        $.ajax({
          type:     'GET',
          url:      OC.filePath('shorty-tracking','ajax','layout.php'),
          data:     { dialog: dialog},
          cache:    false,
          dataType: 'json'
        }).pipe(
          function(response){return Shorty.Ajax.eval(response)},
          function(response){return Shorty.Ajax.fail(response)}
        ).done(function(response){
          // create a fresh dialog
          // insert it alongside the existing dialogs in the top controls bar
          $('#controls').append(response.layout);
          switch (dialog){
            case 'list':
              Shorty.Tracking.Dialog.List=$('#controls #shorty-tracking-list-dialog').first();
              break;
            case 'click':
              Shorty.Tracking.Dialog.Click=$('#controls #shorty-tracking-click-dialog').first();
          } // switch
          dfd.resolve();
        }).fail(dfd.reject)
      } // else
    }); // each
    return dfd.promise();
  },

ベルギの答えで、私はどうやら元の問題を取り除くことができました。これまで、失敗したバインドの試行を検出できませんでした。しかし、私はその提案に完全に従うことはできませんでした。彼の答えでは、直接割り当てを優先して、初期化メソッドのswitchステートメントを削除することを提案しました。これは確かにはるかにエレガントですが、それは機能しません。javascriptが変数に格納されている参照や関数をどのように処理するかについて、私の側には誤解がある印象があります。

たぶん、あなた、ベルギ、または他の誰かがこれについて説明する光を当てることができます:

これは、上から変更された初期化方法です。

  init:function(){
    if (Shorty.Debug) Shorty.Debug.log("initializing tracking list");
    // check if dialogs already exist
    if (   $.isEmptyObject(Shorty.Tracking.Dialog.List)
        && $.isEmptyObject(Shorty.Tracking.Dialog.Click) ){
      // two dialogs are used by this plugin
      var dialogs={
        'list':  Shorty.Tracking.Dialog.List,
        'click': Shorty.Tracking.Dialog.Click
      };
      // load dialogs from server
      var dfds=$.map(dialogs,function(obj,dialog){
        // load dialog layout via ajax and append it to the collection of dialogs in the controls
        return $.ajax({
          type:     'GET',
          url:      OC.filePath('shorty-tracking','ajax','layout.php'),
          data:     { dialog: dialog},
          cache:    false,
          dataType: 'json'
        }).pipe(
          function(response){return Shorty.Ajax.eval(response)},
          function(response){return Shorty.Ajax.fail(response)}
        ).done(function(response){
          // create a fresh dialog and insert it alongside the existing dialogs in the top controls bar
          $('#controls').append(response.layout);
//           obj=$('#controls #shorty-tracking-'+dialog+'-dialog').first();
          switch(dialog){
            case 'list':
              Shorty.Tracking.Dialog.List=$('#controls #shorty-tracking-list-dialog').first();
              break;
            case 'click':
              Shorty.Tracking.Dialog.Click=$('#controls #shorty-tracking-click-dialog').first();
              break;
          } // switch
        })
      }) // map
      return $.when.apply(null, dfds);
    }else{
      // dialogs already loaded, just clean them for usage
      Shorty.Tracking.Dialog.List.find('#list-of-clicks tbody tr').remove();
      new Deferred().resolve();
    } // else
  },

真ん中には、割り当てステートメントがコメントアウトされており、現在、以下のswitchステートメントに置き換えられています。obj.elementなどのいくつかのバリエーションを試しましたが、失敗しました。関数の外では、変数Shorty.Tracking.Dialog.ListおよびShorty.Tracking.-Dialog.Clickは空のままです。

私はWebスタッフとjs/jqueryの完全な初心者です。しかし、私は確かに、参照を処理するこの方法についてもっと知りたいと思っています。

4

1 に答える 1

2

これが問題のあるコードです。

var dfd=new $.Deferred();
$.each(['list','click'], function(){
    ...
    dfd.resolve/fail();
});

Deferredを1つだけ作成しますが、それを複数回解決します。したがって、最初の解決が行われたとき、2番目のAjaxは終了していなかったでしょう。

したがって、代わりに2つの遅延を使用し、を介してそれらを結合しますjQuery.when()。また、自分でDeferredを作成する必要はないと思います。pipe()あなたが電話から得たそれらの2つを取るだけです。

function init() {
   var dialogs={
      'list':  Shorty.Tracking.Dialog.List,
      'click': Shorty.Tracking.Dialog.Click
   };
   var deferreds = $.map(dialogs, function(obj, dialog) {
       return $.ajax(...).pipe(...).done(...
           // really, don't use switch here:
           obj.element = response.layout;
       }); // done() returns the Deferred
   });
   return $.when.apply(null, deferreds);
}

...

$.ready(function($) {
    init().done(...);
});

OK、switch-statementについて説明する必要があります。確かに、dialogsオブジェクトの値は[初期化されていない]変数から割り当てられ、その値(undefined)を保持します。フィールドが再割り当てされても、Shorty値は変更されません。Javascriptには「ポインタ」はありません。dialogswitchステートメントの代わりに、メンバー演算子で現在の変数を使用するのが便利だと思いました。Shorty.Tracking.Dialog.Listとに割り当てるには.Click、次のようなものを使用する必要があります

var dialogs = ["list", "click"];
var shortcut = Shorty.Tracking.Dialog; // some object
for (var i=0; i<dialogs.length; i++) {
    // loop over them,
    // do the ajax stuff
    var element = $(repsonse.layout); // get the added element from the response
    $('#controls').append(element);

    shortcut[dialogs[i]] = element;
}

(最終的には、JavaScriptで文字列の最初の文字を大文字にする方法のスニペットを使用しますか?

于 2012-07-28T16:00:25.263 に答える