web-dev-qa-db-ja.com

JavaScript Qライブラリで同期を約束できますか?

私は次のようなことをしたいです:

delay( 2500 )
  .then( function () { console.log( "Step 1 done" ) } )
  .then( delay( 7500 ) )
  .then( function () { console.log( "Step 2 done" ) } );

したがって、遅延の実装はこれまで何度も実証されてきました。

function delay( ms ) {
  var deferred = Q.defer();
  setTimeout( deferred.resolve, ms );
  return deferred.promise;
}

しかし、node.jsで上記を実行すると、次のようになります。

... delay of 2500ms
Step 1 done
Step 2 done
... delay of ~7500ms

私が期待するものではなく:

... delay of 2500ms
Step 1 done
... delay of 7500ms
Step 2 done

https://github.com/kriskowal/q/wiki/Examples-Gallery で提供されている例では、同期関数(コールバックを伴わずに値を返す関数)の例が見つかりません。 promise関数とチェーンされています。

同期アクションと非同期プロミスを組み合わせる方法はありますか?

私はもう試した:

function synchronousPromise() {
  var deferred = Q.defer();
  console.log( "Synchronous function call" );
  deferred.resolve();
  return deferred.promise;
}

delay( 2500 )
  .then( function(){synchronousPromise()} )
  .then( function(){delay( 7500 )} )
  .then( function(){synchronousPromise()} );

そして、この出力:

... delay of 2500ms
Time now is 2013-06-20
Time now is 2013-06-20
... delay of 7500ms

..まだ私が達成しようとしていることではありません。

15
PP.

コールバックをチェーンしたい場合は、コールバックの1つから新しいpromiseオブジェクトをreturnする必要があります。最初の例では、次のように記述します。

.then( delay( 7500 ) )

これは、promiseオブジェクトを関数ではなく.thenに渡していることを意味します。 Promise/A +提案 (Qが続きます)によると、関数以外の引数はすべて無視する必要があります。つまり、基本的には、次のように書くのと同じです。

delay( 2500 )
  .then( function () { console.log( "Step 1 done" ) } )
  .then( function () { console.log( "Step 2 done" ) } );

代わりに、delayを呼び出してpromiseオブジェクトを返す関数を渡します。

delay( 2500 )
  .then( function () { console.log( "Step 1 done" ); } ) 
  .then( function () { return delay( 7500 ); } )
  .then( function () { console.log( "Step 2 done" ); } );

これで、最後のコールバックは、2番目のコールバックでdelayによって返されたpromiseオブジェクトが解決されたときにのみ呼び出されます。

13
Felix Kling

グーグルは同様の問題を処理している間に私をここに連れてきました(しかしクリスコワルのQを使用して)、私はあなたが以下を行うことを可能にする非常に小さなフレームワークに行き着きました:

var chain = [
  doNext(delay, 2500),
  doNext(console.log, "Step 1 done"),
  doNext(delay, 7500),
  doNext(console.log, "Step 2 done")
];

doInOrder(chain);

フレームワークはわずか12行で、おそらく他のPromiseライブラリに適合させることができます。

var Q = require('q');

function doNext(fn /* , arguments */){
  var args =  Array.prototype.splice.call(arguments, 1);
  return function(prevRetVal){
    // For my needs I didn't need the results from previous fns
    return fn.apply(null, args)
  }
}

function doInOrder(doNexters, init){
  return doNexters.reduce(Q.when, init);
}
3
forforf

BabelまたはTypeScriptを使用する場合は、 ES6 Generators を使用できます。

  'use strict';

  let asyncTask = () =>
    new Promise(resolve => {
      let delay = Math.floor(Math.random() * 1000);

      setTimeout(function () {
        resolve(delay);
      }, delay);
    });

  let makeMeLookSync = fn => {
    let iterator = fn();
    let loop = result => {
      !result.done && result.value.then(res =>
        loop(iterator.next(res)));
    };

    loop(iterator.next());
  };

  makeMeLookSync(function* () {
    let result = yield asyncTask();

    console.log(result);
  });
0
Remo H. Jansen