Опрос до получения конкретного результата?

1

В настоящее время я пытаюсь добавить опрос в мое приложение, используя эту ссылку https://davidwalsh.name/javascript-polling (и многие другие).

У меня есть доступ к следующим уже реализованным api:

client.get('url')
// returns Promise with result of getting result from url
// for the application I am working on,
//     the URL returns json that looks like the following 
//     {status: DONE or IN PROGRESS, other values...}
// when status is DONE other values are what I will use in the application

client.post('url', {data: passAnyDataHere}) 
// sends a post request with result of sending data to url
// starts the specific job

Одна из проблем, с которыми я столкнулся, заключается в том, что при попытке адаптировать код опроса JavaScript, связанный с ним выше, когда я узнаю, что статус DONE, у меня нет способа вернуть результат вне Promise. Может кто-нибудь дать мне советы о том, как это сделать? (опрос до тех пор, пока я не найду определенное значение, а затем верну его значение для использования позже)

Позволь мне привести пример

export default function someFunction() {
    let a = client.get('/status');
    a.then( dataResult => 
      {
         if (dataResult.status == "DONE") {
            //** want to get other values in dataResult here 
            // and store it somewhere else for use later
         }
      });
    // ***want to work with results here.
    // need some way to get the status of what happened inside the .then(..) part
   //  eventually have to return success or failure and results to the frontend
   // (this part is already done)
 }

Основой кода является https://github.com/erikras/react-redux-universal-hot-example#server-side-data-fetching (использует React.js/Node.js/Redux/etc.)

Любые советы/предложения/помощь приветствуются. Спасибо!

Кроме того, приложение, над которым я работаю, не использует JQuery.

Теги:
asynchronous

3 ответа

3

Здесь приведен пример функции, которая использует обещания и опросы, пока вы не получите желаемый результат. Я также параметризую его так, чтобы вы могли пройти в интервале опроса и времени ожидания:

// create a promise that resolves after a short delay
function delay(t) {
    return new Promise(function(resolve) {
        setTimeout(resolve, t);
    });
}

// interval is how often to poll
// timeout is how long to poll waiting for a result (0 means try forever)
// url is the URL to request
function pollUntilDone(url, interval, timeout) {
    let start = Date.now();
    function run() {
        return client.get(url).then(function(dataResult) {
            if (dataResult.status === "DONE") {
                // we know we're done here, return from here whatever you 
                // want the final resolved value of the promise to be
                return dataResult;
            } else {
                if (timeout !== 0 && Date.now() - start > timeout) {
                    throw new Error("timeout error on pollUntilDone");
                } else {
                    // run again with a short delay
                    return delay(interval).then(run);
                }
            }
        });
    }
    return run();
}

// sample usage
// polls every 500ms for up to 30 seconds
pollUntilDone(someUrl, 500, 30 * 1000).then(function(result) {
   // have final result here 
}).catch(function(err) {
    // handle error here
});

Ключевым моментом здесь является объединение ваших обещаний, поэтому каждый раз, когда вы снова вызываете run(), вы возвращаете его значение, чтобы оно было привязано к предыдущему обещанию. Затем, когда вы наконец вернете значение или выбросите исключение, первоначальное обещание получит это значение или ошибку в качестве разрешенного значения или отклоненной причины.

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

  • 0
    Как бы этот рефакторинг не вложил обещания?
  • 0
    @Jonathon - О каком вложении ты говоришь? Это псевдорекурсивный, не вложенный. Если вы собираетесь делать условное ветвление внутри .then() , вам придется делать это так, как здесь. Я не понимаю, какое вложение вы хотите удалить?
Показать ещё 1 комментарий
2

В последних версиях Node.js есть поддержка async/await.

Ниже приведен пример его использования.

Одним из основных преимуществ async/await, очень легко следовать коду и понимать его логику. Если, например, вы хотели продлить это, чтобы иметь максимальную функцию try, было бы тривиально делать. (подсказка) Это просто петля :)

let count = 0;

var client = {
  get: function () {
    return new Promise(function (resolve, reject) {
      count ++;
      setTimeout(function () {
        if (count > 4) resolve({status:'DONE',otherStuff:'Other Stuff'});
        else resolve({status: 'count: ${count}'});
      }, 1000);
    });
  }
}


async function someFunction() {
  while (true) {
    let dataResult = await client.get('/status');
    console.log(dataResult.status);
    if (dataResult.status == "DONE") {
      return dataResult;
    }
  }
}

(async () => { let r = await someFunction(); console.log(r); })();
0

Один из вариантов - изменить функцию poll чтобы разрешить только тогда, когда были выполнены требуемые условия:

function poll(pollFn, interval = 100) {
    var intervalHandle = null

    return {
        until(conditionFn) {
            return new Promise((resolve, reject) => {
                intervalHandle = setInterval(() => {
                    pollFn().then((data) => {
                        let passesCondition = false;
                        try {
                            passesCondition = conditionFn(data);
                        } catch(e) {
                            reject(e);
                        }
                        if (passesCondition) {
                            resolve(data);
                            clearInterval(intervalHandle);
                        }
                    }).catch(reject)
                }, interval)
            })
        }
    }
}

var counter = 0;

function getStatus() {
    if (counter++ === 5) {
       return Promise.resolve({ status: 'DONE', otherStuff: 'hi' });
    }
    console.log('not DONE, keep going')
    return Promise.resolve({ status: 'WORKING' });
}

poll(getStatus, 500)
  .until(data => data.status === 'DONE')
  .then((data) => {
    // do something with the data
    console.log('status is DONE', data)
  })

Ещё вопросы

Сообщество Overcoder
Наверх
Меню