5

同期する必要がある promise オブジェクトがあります。たとえば、最初の約束が完了する前に、2 番目の約束が機能するべきではありません。最初のものが拒否された場合、最初のものを再度実行する必要があります。

いくつかの例を実装しました。これはうまく機能します。getVal を呼び出し、2000ms 待ち、戻り、i++、再度 getVal を呼び出す .....

 getVal() {
       return new Promise(function(resolve, reject) {
      setTimeout(function(){ resolve(19) }, 2000);
         });

     }

async promiseController(){

    for(var i =0;i<5;i++)
      {
        var _val = await this.getVal()
        console.log(_val+'prom');
      }
    }

しかし、promise オブジェクトの配列を制御する必要があります。私がやりたいことは、データがあり、それを5つに分割したことです。最初の部分が処理された後 (例: サーバーに送信)、2 番目の部分を処理したい場合は、最初の部分を再度処理する必要があります。

これは私が作ったプロトタイプの実装です

  getVal() {
   return new Promise(function(resolve, reject) {
  setTimeout(function(){ resolve(19) }, 2000);
     });

 }

async promiseController(){
  var proms=[]
  for(var i =0;i<5;i++)
    {
      proms.push(this.getVal())
    }

for(var i =0;i<5;i++)
  {
    var _val = await proms[i]
    console.log(_val+'prom');
  }
}

このコードの Promise オブジェクトは順次動作します。最初の例として同期的に動作するように、以下のコードを修正するにはどうすればよいですか。

4

4 に答える 4

3
async promiseController(){
  for(const value of array) {
    console.log((await this.getVal(value))+'prom');
  }
}

物事を過度に複雑にする必要はありません。ループ内で呼び出すだけawaitで、必要なものを待ちます。

他の答えが正しく言ったように、約束は操作ではなくを表します。操作には通常の関数が使用されます。

失敗を無視したい場合は.catch(() => {})、約束を守ることができます。失敗するまで再試行する場合は、再試行を関数にリファクタリングして、次のように使用できます。

const retry = fn => (...args) => fn(...args).catch(retry(fn));
于 2016-08-29T19:12:02.763 に答える
1

まぁ、いいよ。私は、適切な関数型プログラミングの目的のために、asyncと をawait避けるべきだと信じています。約束は十分だと思います。それでも、C++ 風の命令型スタイルでコーディングを続けたい場合は、それasyncが最適awaitです。

同期する必要がある promise オブジェクトがあります。たとえば、最初の約束が完了する前に、2 番目の約束が機能するべきではありません。最初のものが拒否された場合、最初のものを再度実行する必要があります。

以下のコードについて簡単に説明します。async()データとコールバック (エラー ファースト タイプ) を受け取る関数があります。デモ用として、2000 ミリ秒以内にデータを使用してコールバックを呼び出そうとしますが、1000 ミリ秒でタイムアウトが発生します。したがって、50-50 は、データまたはエラーでコールバックを呼び出します。

したがって、実際にはプロミスを返すためにそれが必要なので、の助けを借りてそれを約束し、それは関数をpromisify()取りasync()、関数を返しますasyncPro()。これは実際には と同じですがasync()、代わりに promise を返します。thenそのため、ステージでコールバックを使用することが期待されています。

次にtryNTimes(data,asyncFun,n = 5)、データを受け取る関数、約束された非同期関数、および拒否するまでの試行回数を指定する整数が続きます。デフォルトの試行回数は 5 ですが、3 番目の引数を渡すことで任意の値に設定できます。

最後の部分については、flowControl()の助けを借りて約束を完全に結び付ける がありますArray.prototype.reduce()

これで、すべての約束が次々に連鎖し、5 回試行する前に失敗することはありません。

function promisify(fun){
  return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
}

function async(data, callback){
  var dur = Math.floor(Math.random()*2000);
  setTimeout(_ => callback(false,data),dur);           // may resolve before timeout
  setTimeout(_ => callback("error at " + data),1000);  // timeout at 1 sec
}

function tryNTimes(data,asyncFun,n = 5){
  return new Promise((resolve,reject) => { n === 0 && reject("try out fail at 5 tries: " + data);
                                           asyncFun(data).then(v => resolve("resolved at countdown " + n + ": " + v))
                                                         .catch(e => resolve(tryNTimes(data,asyncFun,--n)));
                                         });
}

function flowControl(d,f,tc){
  return d.reduce((prom,chunk) => prom.then(v => { console.log(v);
                                                   return tryNTimes(chunk,f,tc);
                                                 }),Promise.resolve("initial dummy promise"));
}

var data = ["chunk_1", "chunk_2", "chunk_3", "chunk_4", "chunk_5"],
asyncPro = promisify(async);                           // now our async function returns a promise

flowControl(data,asyncPro).then(v => console.log(v))
                          .catch(e => console.log(e));

「5 回試行」エラーをより頻繁に表示したい場合は、async()関数のタイムアウト値を下げてください。

于 2016-08-30T00:35:57.867 に答える
1

最初の promise が解決されるまで「後続の promise を実行」しないことが目標である場合、promise は既に実行中の非同期アクティビティを表すことに注意する必要があります。約束が存在するようになってからでは手遅れです。

代わりに、最初の promise が終了するまで、後続の promise ファクトリ メソッドを呼び出さないようにする必要があります。getVal()最初の例では、前の promise が完了するまで呼び出さないことでこれを行います。

したがって、次のような結果になります。

delay(time) {
    return new Promise(resolve => setTimeout(resolve, time));
}

async promiseController() {
    const factories = [];
    for (let i = 0; i < 5; ++i) {
        factories.push(() => this.getVal());
    }

    for (const f of factories) {
        // keep running this factory until it succeeds
        let success = false;
        while (!success) {
            try {
                const promise = f();
                const result = await f;
                success = true;
                console.log(`result = ${result}`);
            }
            catch (err) {
                console.log("promise failed.  retrying");
                await delay(100);
            }
        }
    }
}
于 2016-08-29T18:58:21.550 に答える