2016-01-07 4 views
9

プロミスチェーンをどのように遅延させることができますか?私はCSSアニメーションが完成するのを待ってからスクリプトを続行したいので、これが必要です。ファンクションを延期する方法

この関数の目的は、ビューを開くことです。ビューがまだ開いていない場合は、(クラスを変更して)開いて、CSSアニメーションを待ってください。ビューがすでに開いている場合は、何も実行せずに続行します。

私はこのような関数を呼び出したい: (それは角コントローラ内の関数である)

$scope.openView(viewId).then(function() {    
    $scope.openAnotherView(anotherViewId); 
}); 


/** Function to open some view **/ 
$scope.openView = function (viewId) { 
    function timeout(delay) { 
     return new Promise(function(resolve, reject) { 
      $timeout(resolve, delay); 
     }); 
    } 

    // Check if view is already open 
    if ($scope.viewId != viewId) { 
     $scope.viewId = viewId;    

     // get data from ajaxcall (also a promise) 
     return MyService.getData(viewId).then(function(data) { 
      // add data to view 
      // change class to open view 
      // this is working ok! 
     }).then(function() { 
      return timeout(30000 /* some large number (testing purpose) */) 
     }); 
    } else { 
     // view is already open, so return here we don't have to wait 
     // return empty promise, with no timeout 
     return new Promise(function(resolve, reject) { 
      resolve() 
     });  
    } 
} 

このコードは動作しますが、遅延が動作していません。私のアプローチは大丈夫ですか?私はここで何が欠けていますか?


編集1:メイン質問Aを明確に

:主な問題のいくつかの明確化:


@sdgluck

から提案編集2でコードを改善もう少し: 私のコードでこの構造を使うことはできますか?

// code doesnt know wheter to wait or not 
// can the Promise do this? 
openView().then(function() {    
    openAnotherView(); 
} 

成果1

ブラウザはopenView()を呼び出しますが、それは既に開いているので、それだけですぐに(遅延なし)openAnotherView()を呼び出します。

成果2

図がopenView()が遅れ、その後、それを開きます(?または@Dominicトビアスが指摘するように、eventlisterを追加)し、いくつかの遅延の後openAnotherView()を呼び出して、開いていません。

ありがとうございました!

編集3:問題とフィドルを追加しましたが http://jsfiddle.net/C3TVg/60/

+1

私はあなたが間違った方法でこれを行うかもしれないと思います。代わりに[this](https://davidwalsh.name/css-animation-callback)のようにアニメーションが完了したかどうかを検出したいかもしれないように思えます。 –

答えて

1

私は約束の連鎖をどのように遅らせることができますか?

$timeoutは約束を返します。 返信です。

$scope.openView = function (viewId) { 
    // Check if view is already open 
    if ($scope.viewId == viewId) { 
     //chain right away with empty promise 
     return $q.when(); 
    }; 

    //otherwise if view is not already open 

    var p = MyService.getData(viewId).then(function(data) { 
      // add data to view 
      // change class to open view 
      // this is working ok! 
    }); 

    var pDelayed = p.then (function() { 
     //return to chain delay 
     return $timeout(angular.noop, 30000); 
     }); 

    //return delayed promise for chaining 
    return pDelayed; 
}; 

$scope.openView(viewId).then(function() { 
    //use chained promise    
    $scope.openAnotherView(anotherViewId); 
}); 
+0

あなたの答えはThx、私はちょうど私の質問を更新しました。私が待たなければならないと、私は今はあらかじめしていないという事実を明確にしようとしました。 – 11mb

+0

条件付き遅延を追加するように更新されました。 – georgeawg

3

の約束を返す必要があります。各then accepts a functionを説明しました。それはPromiseのインスタンスを受け入れません。代わりに、約束の機能timeoutリターンを持って、また

return MyService 
    .getData(viewId) 
    .then(function(data) { 
     // ... 
    }) 
    .then(function() { 
     return timeout(3000); 
    }); 

を::

function timeout(delay) { 
    return function() { 
     return new Promise(function(resolve, reject) { 
      //      ^^^^^^^ (misspelt in your example) 
      $timeout(resolve, delay); 
     }); 
    }; 
} 

そして、あなたの例のように、それを使用することができます。

return MyService 
    .getData(viewId) 
    .then(function(data) { 
     // ... 
    }) 
    .then(timeout(3000)); 
あなたは timeoutにコールを返すようにしたいです
+0

私の間違いをタイムアウト機能で特定し、それを解決するためのThx。しかし、私は@Dominic Tobiasのような私のコードに別の問題があると思っています。 – 11mb

+1

@ 11mb問題ありません。そして、他の答えはより包括的です。 :-) – sdgluck

13

約束を遅らせるには、待ち時間の後にresolve関数を呼び出すだけです。

new Promise(function(resolve, reject) { 
    setTimeout(function() { 
    resolve(); 
    }, 3000); // Wait 3s then resolve. 
}); 

あなたのコードの問題は、あなたが約束を戻ってきているし、その約束のthen内側にあなたが別のものを作成し、それを待つために、元の約束を期待しているということである - 私はそれがどのようにではありません怖いです仕事を約束します。あなたは約束関数内のすべてのあなたの待機を行う必要があり、その後解決呼び出します:

編集:これは真実ではありません、あなたはどのthenに約束チェーンを遅らせることができます。

function promise1() { 
 
    return new Promise((resolve) => { 
 
    setTimeout(() => { 
 
     console.log('promise1'); 
 
     resolve(); 
 
    }, 1000); 
 
    }) 
 
    .then(promise2); 
 
} 
 

 
function promise2() { 
 
    return new Promise((resolve) => { 
 
    setTimeout(() => { 
 
     console.log('promise2'); 
 
     resolve(); 
 
    }, 1000); 
 
    }); 
 
} 
 

 
function promise3() { 
 
    return new Promise((resolve) => { 
 
    setTimeout(() => { 
 
     console.log('promise3'); 
 
     resolve(); 
 
    }, 1000); 
 
    }); 
 
} 
 

 
promise1() 
 
    .then(promise3) 
 
    .then(() => { 
 
    console.log('...finished'); 
 
    })

しかし、これはCSSアニメーションを待つ良い方法ではありません。それはtransitionendイベントに耳を傾け、より良いです:

element.addEventListener('transitionend', onTransitionEnd); 
element.classList.add('transition-me'); 

メモ代わりtransitionanimationを使用している場合、同じ概念がなく、animationendイベントを使用し適用します。

+0

'$ timeout'で' setTimeout'を使うと、_delayがうまく動作しないという問題を解決できません。しかし、移行を待つ方法についての良いアドバイス。 :-) – sdgluck

+0

ああ、私は本当にCSSとjsに複製されたアニメーション/トランジションタイムを嫌っていました。私は間違いなくそれを調べます! あなたの提案について:「表示するデータを追加する」機能の周りにタイムアウトを追加して、私のビューを開く前に待ちますが、最初の呼び出しを遅らせることはできません( 'Everything is ready')。次に( 'openAnotherView')。 私はこのように解決しました:Promise.resolve(); – 11mb

+0

あなたは約束を返すが、それを待たずにいたいのですか? –

関連する問題