轮询直到获得特定结果?

cs_*_*017 5 javascript asynchronous node.js

我目前正在尝试使用此链接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
Run Code Online (Sandbox Code Playgroud)

我遇到的问题之一是,在尝试调整我上面链接的 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)
 }
Run Code Online (Sandbox Code Playgroud)

代码的基础是https://github.com/erikras/react-redux-universal-hot-example#server-side-data-fetching(使用 React.js/Node.js/Redux/etc.)

任何提示/建议/帮助/表示赞赏。谢谢!

此外,我正在处理的应用程序不使用 JQuery。

Kyl*_*Mit 8

这是基于async/await轮询的更具扩展性的解决方案

只需添加以下实用方法:

const poll = async function (fn, fnCondition, ms) {
  let result = await fn();
  while (fnCondition(result)) {
    await wait(ms);
    result = await fn();
  }
  return result;
};

const wait = function (ms = 1000) {
  return new Promise(resolve => {
    setTimeout(resolve, ms);
  });
};
Run Code Online (Sandbox Code Playgroud)

然后你可以这样称呼它:

let fetchReport = () => axios.get(reportUrl);
let validate = result => !result.data.summary;
let response = await poll(fetchReport, validate, 3000);
Run Code Online (Sandbox Code Playgroud)

  • 最干净的解决方案!谢谢 (2认同)

Kei*_*ith 5

Node.js 的最新版本支持 async / await。

下面是一个使用它的例子..

async / await 的一大优势,很容易跟上代码,并理解它的逻辑。例如,如果您想扩展它,以获得最大尝试的功能,那将是微不足道的。(提示)这只是一个 for 循环 :)

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); })();
Run Code Online (Sandbox Code Playgroud)


jfr*_*d00 5

下面是一个函数示例,该函数使用 promise 和 polls 直到您获得所需的结果。我还对其进行了参数化,以便您可以传入轮询间隔和超时值:

// 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 Code Online (Sandbox Code Playgroud)

这里的关键是链接你的承诺,所以每次你run()再次调用时,你都会返回它的值,这样它就会链接到之前的承诺。然后,每当您最终返回一个值或抛出异常时,原始 Promise 都会将该值或错误作为已解决的值或被拒绝的原因。

请注意,我添加了超时,因为您真的不想永远进行轮询,特别是在某些不可预见和重复出现的错误可能不会拒绝承诺但不会得到您想要的结果的情况下。


Rob*_* M. 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)
  })
Run Code Online (Sandbox Code Playgroud)