Уменьшите повторные запросы, возможно, эта библиотека может вам помочь

внешний интерфейс Шаблоны проектирования

Если вам интересна эта библиотека, добро пожаловатьStar Или рисоватьIssueОн также может стать участником этой библиотеки. (Если кто-то поможет перевести на английский или написать тест-кейс, буду признателен.

Если вы хотите перепечатать, просто прокомментируйте, а затем укажите источник и адрес github.

не отменятьPromise, но превращает несколько одинаковых промисов в один!Исполняемая функция все равно будет выполняться, и возвращаемое значение все равно будет, но она не будет генерировать лишниеPromise.

Пожалуйста, представьте следующие два сценария

1

Иногда на одной странице есть несколько разделов, как показано на изображении ниже.

image.png

И в этих частях есть дублирующиеся данные, такие как зеленая часть, они фактически запрашивают один и тот же контент на бэкэнде.

В это время, если мы возьмем запрос к каждому компонентному блоку модуля, очевидно, что три запроса, которые могут совместно использовать возвращаемое значение, повторяются.

Есть ли способ сделать для этих трех повторяющихся запросов только один запрос, а затем использовать одно и то же возвращаемое значение для всех трех запросов?

2

Предположим, есть компонент, обеспечивающий частичное обновление или загрузку.

image.png

Иногда, когда пользователь щелкает, чтобы обновить, из-за дрожания рук или по другим неизвестным причинам, короче говоря, он щелкает более одного раза, может быть, несколько раз, что приводит к прямой отправке нескольких запросов.

Можно ли для этих нескольких запросов интегрировать и отправить только один запрос?

once-init

Конечно, вы можете разработать сложную логику и инкапсулировать относительно безопасный компонент. В качестве альтернативы вы можете попробоватьonce-init?

github npm

npm license npm version

Promise Function Init Once, Use Everywhere.

будет инициализирован только один разPromiseфункция.

будет выполняться при первом вызове объектаPromiseФункция инициализируется, вызывается повторно, и повторная инициализация выполняться не будет.

тот самыйPromiseне будет выполняться дважды одновременно.

размер после сжатияimage.png

обещать

  1. OnceInitупакованныйPromise Function, никогда не будет выполняться дважды одновременно.
  2. если предыдущийPromise FunctionСледующий вызывается без выполненияPromise Function, то следующийPromise Functionподелится предыдущимPromise FunctionизPromise.

Пример

Предположим, естьaxios Promiseзапрос, тип возвращаемого значенияnumber, значение777.

const requestNumber = async () => {
  const res: AxiosResponse<number> = await axiosInstance.get("/api/number");
  return res.data;
};

вы можете использоватьoiинкапсулировать этоPromiseфункция

const oiInstance = oi(requestNumber);

Теперь вы можете вызывать этот экземпляр где угодно.

init

Предположим, есть два методаfunctionAа такжеfunctionA, нужно отправить этот запрос.

async function functionA() {
  ...
  const res = await oiInstance.init();
  ...
}

async function functionB() {
  ...
  const res = await oiInstance.init();
  ...
}

И вам нужно использовать оба метода в определенном файле.

async function functionC() {
  await functionA();
  await functionB();
}

function functionD() {
  functionA();
  functionB();
}

дляfunctionC, существуетпервое исполнениеinitПозже,oiInstanceбудет сохранятьPromiseрезультат выполнения , а затем выполнитьinit,Будубольше не будет выдаватьсяPromiseпросить.

дляfunctionD,apiЗапрос будет отправлен только один раз,functionAа такжеfunctionBсерединаresбудет ждатьтот же запросВозвращаемое значение , не будет отправлять повторяющиеся запросы.

target

targetВозвращаемое значение может быть получено синхронно.

function functionE() {
  ...
  const res = oiInstance.target;
  ...
}

если получитьtargetДо того, как инициализация завершена,targetценностьPromiseвозвращаемое значение, иначеtargetценностьundefined. Например,

const res = oiInstance.target; // undefined
await oiInstance.init();

const res = oiInstance.target; // [Return Value] 777

Обратите внимание, что пока выборка является синхронной,once-initвсе еще будет думать, что вам нужно сделать запрос в этот момент, поэтому позвонитеtargetСвойства также начнут инициализироваться.

В следующем примере мы предполагаемapiПродолжительность запроса составляет10s. В приведенном ниже примере запрос уже был сделан в первой строке.

const res = oiInstance.target; // undefined
/** Promise has been executed. */
setTimeout(async () => {
  const resAfter = oiInstance.target; // [Return Value] 777
  const intAffter = await oiInstance.init(); // [Return Value] 777 , Promise will not be executed again.
  /** Since The Promise has been executed before, it will not be executed again. */
}, 10001);

и синхронно выполняется дважды одновременноinitто же самое, если получитьinitпосетил раньшеtargetсвойства, при доступеtargetвызванныйPromiseЕсли запрос не окончен,initбудет ждать непосредственно предыдущегоPromiseзакончить и вернуться к предыдущемуPromiseВозвращаемое значение.

Следующий пример поможет вам понять.

const res = oiInstance.target; // undefined
setTimeout(async () => {
  const resAfter = oiInstance.target; // undefined
  const intAffter = await oiInstance.init(); // [Return Value] 777
  /** Since The Promise has been executing it will not be executing again.  */
  /** After About 8000ms, The Value will be return by the first promise done */
}, 2000);

здесьinitбудет ждать предыдущегоPromiseВозвращаемое значение выполнения функции, посколькуinitв200msвыполняется после этого, поэтому ему нужно только подождать800msВы можете получить это возвращаемое значение.

defaultValue

использоватьtargetСвойства обычно должны быть связаны со значениями по умолчанию, в то время какoiВторой параметр для васPromiseОпределите значения по умолчанию.

const defaultValue = -1;
const oiInstance = oi(requestNumber, defaultValue);

const ans = oiInstance.target; // -1

refresh

Если вы хотите обновить значение экземпляра, вам нужно позвонитьrefresh.

Предположим, что первое загруженное значение равно777, а значение после обновления равно888.

const ans = await oiInstance.init(); // [Retrun Value] 777
const ansAfterRefresh = await oiInstance.refresh(); // [Retrun Value] 888

После освежения звонитеinitа такжеtargetПриобретенное значение становится новым значением.

oiInstance.target; // undefined
await oiInstance.init(); // [Promise Retrun Value] 777
oiInstance.target; // 777
await oiInstance.refresh(); // [Promise Retrun Value] 888
/** Promise will not be exectued */
oiInstance.target; // 888
await oiInstance.init(); // 888

вы можете напрямую использоватьrefreshвыполнить инициализацию, при инициализации это иinitЭффект тот же.

oiInstance.target; // undefined
await oiInstance.refresh(); // [Promise Retrun Value] 777
oiInstance.target; // 777
await oiInstance.refresh(); // [Promise Retrun Value] 888
oiInstance.target; // 888

Если синхронизация вызывается дважды подрядrefresh,дваждыrefreshбудет ждатьтот же запросВозвращаемое значение , не будет отправлять повторяющиеся запросы.

async function functionA() {
  console.log("A", await oiInstance.refresh());
}
async function functionB() {
  console.log("B", await oiInstance.refresh());
}
functionA(); // 'A', [Promise Retrun Value] 777
functionB(); // 'B', [Promise Retrun Value] 777
/** only one promise is executed */
/** functionA and functionB share A same promise and promise return value */

мы все еще предполагаемapiЗапрашиваемая продолжительность10s === 10000ms.

oiInstance.refresh();
setTimeout(async () => {
  await oiInstance.refresh();
}, 2000);
/** After 10000ms, two refresh will be exected at the same time */

Если асинхронно вызывается дваждыrefresh, затем отправьте запрос дважды.

async function functionA() {
  console.log("A", await oiInstance.refresh());
}
async function functionB() {
  console.log("B", await oiInstance.refresh());
}
await functionA(); // 'A', [Promise Retrun Value] 777
await functionB(); // 'B', [Promise Retrun Value] 888
/** Two different promises were executed */

Если вы считаете, что логика слишком сложна, пожалуйста, запомните хотя бы одну вещь,OnceInitупакованныйPromise Function, никогда не будет выполняться дважды одновременно.

Помимо,once-initтакже предоставляет другиеapi, чтобы удовлетворить больше потребностей, но выше его основные функции. Для получения дополнительной информации см.github для однократной инициализации.

HELP

Я также опубликуюVue3-Composition Apiверсия. (Запланированное)

export abstract class RefOnceInit<T, G = T> extends OnceInit<
  Ref<T | undefined>,
  G
> {
  loading = ref<boolean>(false);
  protected abstract factory(raw: G, observe: Ref<T | undefined>): void;
  constructor(defaultValue?: T) {
    const refed = ref<T>();
    refed.value = defaultValue;
    super(refed);
    this.onLoading((event) => {
      this.loading.value = event;
    });
  }
}

такRefOnceInitявляется отзывчивым объектом. оOnceInitСм. исходный код класса.

Когда запрос завершен, страница может быть запущенаUIИзменение.