一次请求有限数量的端点

j-0*_*e-z 5 javascript es6-promise

我尝试编写一个函数,一次仅请求有限数量的模拟端点。一旦一个请求得到解决,下一个请求就会被获取。这是我的代码:

const requestQueue = (endpoints, callback, limit = 3) => {
    while (endpoints.length > 0) {
        if (limit > 0) {
            const slice = endpoints.splice(0, limit)
            for (const endpoint of slice) {
                limit--
                fetchMock(endpoint)
                    .then(data => callback(data))
                    .catch(err => callback(err))
                    .finally(() => limit++)
            }
        }
    }
}

function fetchMock(endpoint) {
    return Promise.resolve(endpoint)
}

requestQueue([1, 2, 3, 4, 5], data => console.log(data))
Run Code Online (Sandbox Code Playgroud)

它陷入无限循环并崩溃。我错过了什么或误解了什么?请帮助。

You*_*saf 1

无限循环的原因是limit变量在循环内减为零for of;因此,while循环的条件endpoints.length > 0永远不会被计算为false

始终endpoints.length大于零,因为您不会让循环if在第一次迭代后进入块。第一次迭代后,limit为零,因此第一次迭代后limit > 0不是。true结果,循环陷入了无限循环。

现在你可能会说:“但是我已经增加了回调limit内部的值finally,所以limit并不总是零”

为了limit增加,finally必须执行 的回调函数,但这永远不会发生,因为异步代码(thencatchfinally回调被异步调用)是在同步代码执行结束执行的,但在您的情况下,同步代码执行永远不会结束,因为它被困在while循环中。您没有给finally回调机会执行。

事实上,您的代码中没有调用任何 Promise 回调,因为同步代码执行必须结束才能调用它们,而您希望在调用异步回调后结束同步代码执行。您的代码陷入了僵局。


由于您希望在任何最初启动的请求完成后立即向另一个端点发起请求,因此以下代码显示了这一操作:

let offset = 0;

function makeRequest(endpoints, callback) {
  console.log('fetching endpoint ' + endpoints[offset]);
  fetchMock(endpoints[offset++])
    .then(callback)
    .catch(callback)
    .finally(() => {
      if (offset < endpoints.length) {
        requestQueue(endpoints, callback);
      }
    });
}

const requestQueue = (endpoints, callback, limit = 3) => {
  if (offset >= endpoints.length) {
    return;
  }

  if (offset === 0) {
    for (let i = 0; i < limit; i++) {
      makeRequest(endpoints, callback);
    }
  } else {
    makeRequest(endpoints, callback);
  }
};

function fetchMock(endpoint) {
  // random delay between 1 to 4 seconds
  const randomDelay = (Math.random() * (5 - 1) + 1) * 1000;
  return new Promise(res => setTimeout(res, randomDelay, endpoint));
}

requestQueue([1, 2, 3, 4, 5], data => console.log(data));
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 100% !important; top: 0; }
Run Code Online (Sandbox Code Playgroud)