angular - چگونه میتوانم از retry از Rxjs در تابع await خود استفاده کنم؟


من باید یک تابع await را از بلوک کد خود بازگردانم، حالا وقتی تابع await فراخوانی میشود و بار اول شکست میخورد، میخواهم دوباره آن را امتحان کنم و اگر بار دوم هم شکست خورد.. پیغام خطا نشان خواهم داد.

این کد من است

async makeCall(inputs: myInputs): Promise<Instance> {

    const emailOptions: CreateOptions = {
      to: inputs.toPhone,
      from: this.config.accountPhoneNumber
    };

    if (inputs.toPhone) {
      emailOptions.sendText = inputs.toPhone;
    }

    return await this.sample.create(emailOptions);
}

من چیزی شبیه این میخواهم یا پیشنهادی دارید؟ مثل Retry از RxJs

 for(var i = 0; i < 1; i++)
      {
        var result = await this.sample.create(emailOptions);
        if(result)
        {
          // break the loop
          return result;
        }
      }
       // if we land here, so the number of retries was exceeded
       throw Error("...");

پاسخ شماره ۱

شما میتوانید از این کد مقاله استفاده کنید که به نظر میرسد دقیقاً همان چیزی است که نیاز دارید. این کد از تعداد دفعات تلاش مجدد و پیام خطای سفارشی پشتیبانی میکند.

import './style.css';
let i = 0;
const promiseFn = () => {
  const condition = i === 0;
  i++;
  return condition ? Promise.reject() : Promise.resolve();
};

const retryWithDelay = async (
  fn: any,
  retries = 3,
  finalErr = 'Retry failed'
) => {
  try {
    // try
    await fn();
  } catch (err) {
    // if no retries left
    // throw error
    if (retries <= 0) {
      console.log('error');
      return Promise.reject(finalErr);
    }
    //recursively call the same func
    return retryWithDelay(fn, retries - 1, finalErr);
  }
};

retryWithDelay(promiseFn, 2)
  .then(() => {
    console.log('final success');
  })
  .catch(() => {
    console.log('final error');
  });

نسخه نمایشی Stackblitz

پاسخ شماره ۲

گاهی اوقات، یک رویکرد عمومی، بدون RxJs سادهتر و بهتر است ;)

در اینجا یک روش کلی (قابل انعطاف و قابل استفاده مجدد) برای تلاش دوباره یک عملیات غیرهمزمان آورده شده است:

// retry-status object:
//  - "index": retry index, starting from 0
//  - "duration": retry overall duration, in ms
//  - "error": last error, if available
type RetryStatus = { index: number, duration: number, error?: any };

// retry-status callback;
type RetryCB<T> = (s: RetryStatus) => T;

type RetryOptions = {
    // maximum number of retries (infinite by default),
    // or a callback to indicate the need for another retry;
    retry?: number | RetryCB<Boolean>,

    // retry delays, in ms, or a callback that returns them;
    delay?: number | RetryCB<number>,

    // error notifications;
    error?: RetryCB<void>
};

// retries async operation returned from "func" callback, according to options;
// note that "func()" will receive "error" = undefined when "index" = 0.
function retryAsync<T>(func: RetryCB<Promise<T>>, options?: RetryOptions) {
    const start = Date.now();
    let index = 0, e: any;
    let {retry = Number.POSITIVE_INFINITY, delay = -1, error} = options ?? {};
    const s = () => ({index, duration: Date.now() - start, error: e});
    const c: () => Promise<T> = () => func(s()).catch(err => {
        e = err;
        typeof error === 'function' && error(s());
        const r = typeof retry === 'function' ? retry(s()) : retry--;
        const d = typeof delay === 'function' ? delay(s()) : delay;
        index++;
        const t = () => r ? c() : Promise.reject(e);
        return d >= 0 ? (new Promise(a => setTimeout(a, d))).then(t) : t();
    });
    return c();
}

شما هنوز هم میتوانید از آن با RxJs استفاده کنید، البته، زیرا کاملاً عمومی است. شما فقط یک تابع که درخواست غیرهمزمان شما را ایجاد میکند، به همراه چند پارامتر اختیاری، به آن میدهید.

کد بالا از این گیت گرفته شده است.