Вызывайте функцию asyn c снова и снова, пока ожидаемый результат не будет равен Node JS - PullRequest
0 голосов
/ 17 февраля 2020

Допустим, у меня есть 4 задачи

  1. Сделать снимок экрана веб-сайта (с использованием некоторого API-сервиса)
  2. Загрузить снимок экрана на локальный жесткий диск
  3. Загрузить снимок экрана с локального жесткого диска в Google Cloud Bucket
  4. Используйте G C -Vision API для обнаружения текста на этом снимке экрана

Если результат задачи № 4 равен -1, это означает, что я не нашел то, что искал, поэтому мне нужно делать это снова, пока результат не будет равен -1 (что, вероятно, означает, что я нашел то, что мне нужно).

Теперь немного кода:

const screenshot = require("./thum/takeScreenshot");
const googleVisionAPI = require("./gc-vision-api/findTextInButton");
const matchURL = /^((http[s]?|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(.*)?(#[\w\-]+)?$/;
const UploadToGcBucket = require("./gc-storage/saveScreenshot");
const downloadImage = require("./downloadFile");

// let's wait for the bucket to replicate before searching text
function timeout(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const workHard = async () => {
  // 1. Take a screenshot
  const takeAscreenShot = async () => {
    let scShotTaken = await `https:${screenshot.thumURL}`;
    console.log("screenshot captured!!! ", scShotTaken);
    return scShotTaken;
  };

  //  2. Download it to local hard-drive
  const downloadScreenshot = async url => {
    let download = await downloadImage.downloadImage(url);
    return download;
  };

  // 3. Upload it to Google Cloud Bucket
  const uploadToGCBucket = async () => {
    let upload = await UploadToGcBucket.UploadToGcBucket();
    return upload;
  };

  // 4. Check if the appointment's button is present
  const checkMagicButton = async () => {
    // wait a little bit for replication
    await timeout(5000);

    let searchAppointment = await googleVisionAPI.findMagicButton(
      `some_picture_in_a_cloud_bucket.jpg`
    );
    return searchAppointment;
  };

  takeAscreenShot()
    .then(pic => {
      // Verify if it looks like a URL
      let verifyURL = matchURL.test(pic);

      if (!verifyURL) {
        return "The screenshot doesn't look like a valid URL, check the Thumb API";
      }

      downloadScreenshot(pic)
        .then(() => {
          uploadToGCBucket()
            .then(() => {
              checkMagicButton()
                .then(button => {
                  if (button === -1) {
                    throw new Error();
                  }
                })
                .catch(makeCatch("AI finding button ERROR"));
            })
            .catch(makeCatch("Uploading to GC Bucket ERROR"));
        })
        .catch(makeCatch("Downloading ERROR"));
    })
    .catch(makeCatch("ScreenShot ERROR"));
};

const makeCatch = msg => err => {
  console.log("Problem with " + msg, err);
  throw new Error(); // this is important- this rejects the Promise, so it stops the hardWork
};

const tryWork = () => {
  workHard().catch(error => {
    setInterval(tryWork, 5000);
  });
};

tryWork();

так что ... как мне снова вызвать HardWork (), скажем, через 5 минут, если я не найду то, что мне нужно.

1 Ответ

3 голосов
/ 17 февраля 2020

Вы уже используете async функции, и все уже выглядит на основе Promise, так что вы можете сделать hardWork async и затем await каждое Promise внутри него. Если окончательное задание не выполнено, отклоните. В вызывающем hardWork, если Обещание в конечном итоге отклоняется, установите тайм-аут, чтобы вызвать его снова через 5 минут, в противном случае все готово:

const hardWork = async () => {
  // I assume this next line was psuedo-code for an API call or something
  await `https:${screenshot.thumURL}`;

  const image = await downloadImage.downloadImage();
  await UploadToGcBucket.UploadToGcBucket(image);
  await timeout(5000);
  const button = await googleVisionAPI.findMagicButton(`some_screenshot.jpg`);
  if (button === -1) {
    throw new Error();
  }
  // success
};

const tryWork = () => {
  hardWork()
    .catch((error) => {
      setTimeout(tryWork, 5 * 60 * 1000); // 5 minutes
    });
};
tryWork();

Если вам нужны разные сообщения об ошибках для различных возможных ошибки, я бы сделал функцию более высокого порядка, которую вы можете передать в .catch, которая регистрирует сообщение, чтобы сохранить код DRY:

const makeCatch = msg => (err) => {
  console.log('Problem with ' + msg, err);
  throw new Error(); // this is important- this rejects the Promise, so it stops the hardWork
};

// ...

await downloadImage.downloadImage()
  .catch(makeCatch('downloadImage'));
await UploadToGcBucket.UploadToGcBucket(image)
  .catch(makeCatch('upload to gc'));
await timeout(5000);
const button = await googleVisionAPI.findMagicButton(`some_screenshot.jpg`)
  .catch(makeCatch('findButton'));

Живой фрагмент:

// dummied up API calls below...
const timeout = ms => new Promise(resolve => setTimeout(resolve, ms));
const downloadImage = () => new Promise(resolve => setTimeout(resolve, 200));
const uploadToGcBucket = () => new Promise(resolve => setTimeout(resolve, 200));
// the below function will resolve to -1 70% of the time, and to 0 30% of the time
const findMagicButton = () => new Promise(resolve => setTimeout(resolve, 200, Math.floor(Math.random() - 0.7)));
// dummied up API calls above...

const hardWork = async () => {
  const image = await downloadImage();
  await uploadToGcBucket(image);
  await timeout(500);
  const button = await findMagicButton(`some_screenshot.jpg`);
  if (button === -1) {
    throw new Error();
  }
  console.log('success');
};

const tryWork = () => {
  hardWork()
    .catch((error) => {
      console.log('failure, retry');
      setTimeout(tryWork, 2 * 1000); // 2 seconds
    });
};
console.log('start');
tryWork();
...