2016-09-02 15 views
0

私のコントローラ上で同時に機能を実行すると、いくつかの非同期エラーが発生します。各コントローラはいくつかのデータを取り、テストのためにサービス内のメソッドを呼び出します。サービスはコントローラに約束を返し、渡されたデータを操作して約束を解決します。サービスのためのコードのアウトラインので、次のようになります。1つのサービスを持つAngularJS複数のコントローラ:非同期エラー

<!-- language: lang-js --> 
//Service that our controller can access 
app.service("testing", function($timeout, $q) { 

    //Test function which takes a group, and returns a promise with the result 
    this.Test = function(resultsLocation, testList, testFunction) { 
    //promise we are returning 
    var deferred = $q.defer(); 
    var i = 0; 

    //TestCallback loop 
    TestCallBack = function(testList) { 
     if (i < testList.length) { 

      //perform a test on one item of the list 
      testFunction(testList[i]).then(function() { 
       //push result back to controller 
       resultsLocation.push(testList[i].result); 
       i++; 

       //show result of that one item with scope update. 
       //also looks visually pleasing to see test come in 
       //one at a time 
       $timeout(function() { 
        TestCallBack(testList); 
       }, 100); 
      }); 
     } else { 
      //we are done. Resolve promise 
      deferred.resolve("Done"); 
     } 
    }; 

    //initiate loop 
    TestCallBack(testList); 

    //return promise 
    return deferred.promise; 
    }; 

});//testing Service 

そして私は、おおよそ次のようになり、いくつかのコントローラを持っている:

<!-- language: lang-js --> 
//Peripheral 
app.controller("peripheral#", function($scope, testing) { 
    //self stuff 
    $scope.Title = "Peripheral#"; 
    $scope.Summary = ""; 
    $scope.Results = new Array(); 

    //initial lin tests 
    var DiagnosticsList = [ 
     //test1 
     //test2 
     //etc... 
    ]; 

    //Tests routine 
    $scope.Testing = function() { 
     //reset results 
     $scope.Results = new Array(); 
     $scope.Summary = "Testing..."; 

     //Do Tests 
     testing.Test($scope.Results, DiagnosticsList, CustomTestingFunction1).then(
      function(result) { 
       $scope.Summary = "Testing..."; 
      }, 
      function(error) { 
       console.log("Error testing Peripheral1"); 
      } 
     ); 
    }; 
}); 

「テストは、」HTMLでボタンを押した上で呼ばれています。問題は、controller1が "Testing"を呼び出し、次にcontroller2が "Testing"を呼び出す場合、コントローラ1では約束が決して解決されないということです。さらに悪いことに、いくつかのテスト結果がコントローラ2の結果にプッシュされます。

おそらく私は何かが不足しているかもしれませんが、コントローラが持っているときにサービスがそれ自身のインスタンスになると私はどこかで読んでいます。

とにかく、ここでの動作を実証plunkerです:https://plnkr.co/edit/fE5OD35LaXHWrhv0ohq2?p=preview

は、「テスト」は、個別に細かいですが、他のコントローラがテストしている間、あなたは「テスト」を押すと、あなたがそのようなものの値として異常な動作を取得します押します最初のコントローラはテストを終了しません。

+0

あなたには再入国の問題があります。最初の呼び出しが解決される前に、あなたのサービスの 'Test'メソッドをもう一度呼び出すと、あなたはそれへの参照を失ってしまいました。 Angularのサービスはシングルトンだと思います。 –

+0

それはそれを説明します。私はサービスがシングルトンではないどこかを読んだことを誓っていました。工場シングルトンも同様ですか?完了するまでシングルトンの実行をブロックする方法はありますか?あるいは、それが非シングルトンであるかのようにサービスを動作させますか?申し訳ありませんが、私はかなり新しく角張っており、約束のアイデアはすべて一緒になっています。 – Sonic1015

答えて

0

問題はサービスがローカル匿名関数への参照に、グローバル変数TestCallBackを割り当てることです。代わりにという名前のをサービス関数スコープで宣言します。

app.service("testing", function($timeout, $q) { 

    //Test function which takes a group, and returns a promise with the result 
    this.Test = function(resultsLocation, testList, testFunction) { 
     //promise we are returning 
     var deferred = $q.defer(); 
     var i = 0; 

     //TestCallback loop 
    //DONT use global variable 
    //TestCallBack = function(testList) { 
    //INSTEAD use a named function 
    function TestCallBack(testlist) { 
      if (i < testList.length) { 

DEMO on PLNKR


だからvarが関数内で宣言した場合でもグローバルスコープでそれを置くよう関数を宣言、明確にしますか?

エラーは、の値を変数に設定していました。

に宣言されていない変数を代入すると、割り当てが実行されるときに暗黙的にグローバル変数(グローバルオブジェクトのプロパティになります)として作成されます。宣言したと宣言されていない変数間の違いは次のとおりです。

  1. 宣言された変数は、それらが宣言された実行コンテキストに拘束されています。宣言されていない変数は常にグローバルです。

  2. 宣言された変数は、コードが実行される前に作成されます。宣言されていない変数は、それらに割り当てられたコードが実行されるまで存在しません。

  3. 宣言された変数は、実行コンテキスト(関数またはグローバル)の設定​​不可能なプロパティです。宣言されていない変数は構成可能である(例えば削除することができる)。

これらの3つの違いのために、変数を宣言しないと予期しない結果になる可能性が非常に高くなります。したがって、は、関数がグローバルスコープにあるかどうかにかかわらず、常に変数を宣言することをお勧めします。 ECMAScript 5 strictモードでは、宣言されていない変数に代入するとエラーが発生します。この場合1

service.Test関数が二度目と呼ばれていた場合、グローバル値TestCallBackservice.Test関数の第二のインスタンスに匿名関数を参照することによって置き換えられました。匿名のTestCallBack関数は、service.Test関数のクロージャー2を参照しています。クロージャは、関数と、その関数が作成された環境という2つの要素を組み合わせた特別な種類のオブジェクトです。したがって、最初のインスタンス化によってスケジューリングされた関数は、service.Test関数の2番目のインスタンス化のclosureに、iresultsLocationを切り替えていました。

+0

ありがとう、これは私の問題を解決します。だから、明確にするために、関数をvarとして宣言すると、関数内で宣言されても、グローバルスコープに置かれますか? – Sonic1015

+0

「関数をvarとして宣言する」ということはありません。 'var'は、プリミティブまたはリファレンスのいずれかのコンテナです。関数* reference *にvarを割り当てる*ことができます。 varは別のリファレンス(またはプリミティブ)に再割り当てできます。 'service.test'関数の2回目の呼び出しでは、グローバル変数を別の実行コンテキストとクロージャを使用していた関数参照に*再割り当てしました。 – georgeawg

+0

素晴らしいです、説明をいただきありがとうございます – Sonic1015

関連する問題