web-dev-qa-db-ja.com

promise.race()の使用法を理解する

私の知る限り、 promise には2つのオプションがあります。

OK、promise.all()が何をするか知っています。 promiseを並行して実行し、_.then_が両方とも正常に解決された場合に値を提供します。次に例を示します。

_Promise.all([
  $.ajax({ url: 'test1.php' }),
  $.ajax({ url: 'test2.php' })
])
.then(([res1, res2]) => {
  // Both requests resolved
})
.catch(error => {
  // Something went wrong
});
_

しかし、私はpromise.race()が何をするのか正確にわからないのですか?言い換えれば、それを使用しないこととの違いは何ですか?これを仮定します:

_$.ajax({
    url: 'test1.php',
    async: true,
    success: function (data) {
        // This request resolved
    }
});

$.ajax({
    url: 'test2.php',
    async: true,
    success: function (data) {
        // This request resolved
    }
});
_

見る? promise.race()を使用していないので、promise.race()のように動作します。とにかく、promise.race()を正確に使用する必要がある場合を示すシンプルでわかりやすい例はありますか?

9
Martin AJ

ご覧のとおり、race()は、最初に解決または拒否されるpromiseインスタンスを返します。

_var p1 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 500, 'one'); 
});
var p2 = new Promise(function(resolve, reject) { 
    setTimeout(resolve, 100, 'two'); 
});

Promise.race([p1, p2]).then(function(value) {
  console.log(value); // "two"
  // Both resolve, but p2 is faster
});_

シーンを使用するために、リクエストのコスト時間を制限したい場合があります:

_var p = Promise.race([
    fetch('/resource-that-may-take-a-while'),
    new Promise(function (resolve, reject) {
         setTimeout(() => reject(new Error('request timeout')), 5000)
    })
])
p.then(response => console.log(response))
p.catch(error => console.log(error))
_

race()を使用すると、返されたpromiseを取得するだけでよく、race([])のどのpromiseが最初に返されるかを気にする必要はありません。

ただし、例のようにraceがない場合は、どちらが最初に返され、両方のsuccessコールバックでコールバックを呼び出すかを考慮する必要があります。

24
JiangangXiong

タイムアウトシステムを構築することは、次のとおりです。

  1. 要求/計算は別のチャネルによってキャンセルされる場合があります
  2. 後で使用されますが、インタラクションnowが必要です。

2番目の例では、スピナーを「瞬時に」表示する一方で、実際のコンテンツが十分な速さで表示される場合はデフォルトのままにします。以下を数回実行してみてください-少なくともいくつかのコンソールメッセージが「即座に」来ることに注意してください。これは通常、UIで操作を実行するために添付される場合があります。

注意すべき重要な点は、Promise.raceの結果は副作用よりもはるかに重要ではありません(ただし、これはコードの匂いです)。

// 300 ms _feels_ "instant", and flickers are bad

function getUserInfo(user) {
  return new Promise((resolve, reject) => {
    // had it at 1500 to be more true-to-life, but 900 is better for testing
    setTimeout(() => resolve("user data!"), Math.floor(900*Math.random()));
  });
}

function showUserInfo(user) {
  return getUserInfo().then(info => {
    console.log("user info:", info);
    return true;
  });
}

function showSpinner() {
  console.log("please wait...")
}

function timeout(delay, result) {
  return new Promise(resolve => {
    setTimeout(() => resolve(result), delay);
  });
}
Promise.race([showUserInfo(), timeout(300)]).then(displayed => {
  if (!displayed) showSpinner();
});

captainkovalskyによるコメント へのインスピレーションクレジット。

最初の例:

function timeout(delay) {
  let cancel;
  const wait = new Promise(resolve => {
    const timer = setTimeout(() => resolve(false), delay);
    cancel = () => {
      clearTimeout(timer);
      resolve(true);
    };
  });
  wait.cancel = cancel;
  return wait;
}


function doWork() {
  const workFactor = Math.floor(600*Math.random());
  const work = timeout(workFactor);
  
  const result = work.then(canceled => {
    if (canceled)
      console.log('Work canceled');
    else
      console.log('Work done in', workFactor, 'ms');
    return !canceled;
  });
  result.cancel = work.cancel;
  return result;
}

function attemptWork() {
  const work = doWork();
  return Promise.race([work, timeout(300)])
    .then(done => {
      if (!done)
        work.cancel();
      return (done ? 'Work complete!' : 'I gave up');
  });
}

attemptWork().then(console.log);

これから、タイムアウトが最初にヒットしたときにタイムアウトのconsole.logが実行されないことがわかります。テストの便宜上、約半分/半分で失敗/成功するはずです。

5
Iiridayn

要求のバッチ処理に使用しました。長時間実行するには、数万のレコードをバッチにバッチ処理する必要がありました。並行して行うことはできましたが、保留中のリクエストの数が手に負えないようにしたくありませんでした。

async function batchRequests(options) {
    let query = { offset: 0, limit: options.limit };

    do {
        batch = await model.findAll(query);
        query.offset += options.limit;

        if (batch.length) {
            const promise = doLongRequestForBatch(batch).then(() => {
                // Once complete, pop this promise from our array
                // so that we know we can add another batch in its place
                _.remove(promises, p => p === promise);
            });
            promises.Push(promise);

            // Once we hit our concurrency limit, wait for at least one promise to
            // resolve before continuing to batch off requests
            if (promises.length >= options.concurrentBatches) {
                await Promise.race(promises);
            }
        }
    } while (batch.length);

    // Wait for remaining batches to finish
    return Promise.all(promises);
}

batchRequests({ limit: 100, concurrentBatches: 5 });
5
ChristopherJ

promise.race()の使用を理解する簡単な例を次に示します。

サーバーからいくつかのデータを取得する必要があり、データのロードに時間がかかりすぎる場合(15秒など)、エラーを表示したいとします。

2つのpromiseでpromise.race()を呼び出します。1つ目はajaxリクエストで、2つ目は単純なsetTimeout(() => resolve("ERROR"), 15000)です

3
thelmuxkriovar

以下のようなPromise.raceの回避策のサンプルを見てみましょう。

const race = (promises) => {
    return new Promise((resolve, reject) => {
        return promises.forEach(f => f.then(resolve).catch(reject));
    })
};

race関数はすべてのプロミスを実行しますが、最初に終了した人はラッパーPromiseで解決/拒否します。

1
rab

概要:

_Promise.race_は、Promiseの反復可能オブジェクト(たとえば、Array)を引数として受け入れるJS組み込み関数です。この関数はasynchronously iterableに渡されたPromiseのいずれかが解決または拒否されるとすぐにPromiseを返します。

例1:

_var promise1 = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Promise-one'), 500);
});

var promise2 = new Promise((resolve, reject) => {
    setTimeout(() => resolve('Promise-two'), 100);
});

Promise.race([promise1, promise2]).then((value) => {
  console.log(value);
  // Both resolve, but promise2 is faster than promise 1
});_

この例では、最初にPromiseの配列が_Promise.race_で渡されます。 promiseは両方とも解決しますが、promise1はより速く解決します。したがって、promiseはpromise1の値(ストリング_'Promise-one'_)で解決されます。

例2:

_const promise1 = new Promise((resolve, reject) => {
    setTimeout(() => resolve('succes'), 2000);
});

const promise2 = new Promise((resolve, reject) => {
    setTimeout(() => reject('err'), 1000);
});

Promise.race([promise1, promise2])
  .then((value) => {
  console.log(value);
}).catch((value) => {
  console.log('error: ' + value);
});_

この2番目の例では、最初のプロミスが解決できるよりも速く2番目のプロミスが拒否されます。したがって、_Promise.race_は、Promise2が拒否した値である_'err'_の値を持つ拒否されたプロミスを返します。

理解すべき重要な点は、_Promice.race_はPromiseの反復可能要素を取り、その反復可能要素(対応するresolve()またはreject()値で最初に解決または拒否された約束に基づいてPromiseを返すことです。 )。

1