首页 > 解决方案 > 如何使用 promise 执行函数并通过 API 调用多次检查其值并使用该值执行另一个函数?

问题描述

我正在开发一个应用程序,我需要在一个函数中进行 API 调用,然后使用它的值进行另一个 API 调用。但是第一个 API 调用的值并不容易获得,因为它取决于一些外部因素。因此,在进行第一次 API 调用后,我需要以 5 秒的间隔进行 3 次 API 调用,以检查该值是否可用。如果是,则进行第二次 API 调用,否则不要进行第二次 API 调用。

现在我知道我必须这样做 Promises 并且我尝试这样做,但我不确定我所做的是否正确。

这就是我可以对 Promise 函数做的事情:

const promiseFunc = ( param1, param2 ) => {

     return new Promise(( resolve, reject ) => {
           
          const func1 = api1( param1 );

          if ( func1.code === '200' ) {
      
                const startInterval = setInterval( () => {
 
                       const check = getValue();

                              if ( check && check === param2 ) {
                                    clearInterval( startInterval );
                                    resolve();
                               } else {
                                    reject();
                               }
                       
                }, 5000);

          } else {
                reject();
          }

     });

}

所以在上面的 func 中发生的事情是它需要两个参数来调用 api 调用。 func1执行,如果返回 200,则启动间隔计时器。请注意,api1函数调用是 API 调用。我尝试在那里使用 await 但它会引发错误。而且我不确定我是否可以在 Promise 函数中使用 async/await。

继续前进,check变量开始进行 api 调用(getValue()也是一个包含 api 端点的函数)以检查该值是否可用。如果是则解决,如果不是则拒绝。

这是我按顺序执行 promiseFunc 的方式:

promiseFunc( myChosenValue1, myChosenValue2 )
     .then( data => {
            return promiseFunc( valueFromFirstExecution1, valueFromFirstExecution2 )       
     })
     .then( () => {
           console.log( 'Successfully executed both the functions' );
     })
     .catch( e => {
           console.log( e );
     });

这是我编写 Promise 函数所能做的最远的事情,我知道上面的代码中有多个问题。第一个函数得到正确执行,但随后出现此错误TypeError: Cannot read property 'code' of undefined。另外,我不确定 setInterval 中的 API 调用是否会运行。有什么想法吗?

标签: javascriptasynchronouspromise

解决方案


所以你有几件事在这里发生:

  1. 您想轮询服务器端进程以完成
  2. 您想使用服务器端进程成功完成的结果调用另一个函数。

所以让我们写一些助手:

// We need a way to wait for some amount of time before
// retrying a request, sleep sleeps for n milliseconds
const sleep = (n) => new Promise(res => setTimeout(res, n));

// We need a unique sentinel value so we know when we have actual
// results from an API call instead of this default value
const sentinel = {}; // or Symbol, whatever unique you prefer

// poll will take the data necessary to make a fetch
// request and repeat it every `interval` milliseconds
// up to `maxRetries` until it gets a result
const poll = async (url, fetchOpts, interval, maxRetries) => {
  let result = sentinel; // default value
  let ticker = 0; // current number of retries
  while (result === sentinel && ticker < maxRetries) {
    // make the api call
    const resp = await fetch(url, fetchOpts);
    const data = await resp.json();

    // do we have a result?
    if (isDone(data)) { // whatever criteria == completion
      result = data; // breaks the loop
    } else {
      // wait `interval` milliseconds and try again.
      ticker++;
      await sleep(interval);
    }
  }

  // Oops! We didn't get an answer back from the
  // api in time
  if (result === sentinel) {
    throw new Error('Exceeded maxRetries!');
  }

  return result;
};

所以现在我们实际上可以做我们想做的事情了:

// call this with the eventual result, *if* we
// get one
const onSuccess = (result) => {...}; // whatever

// This is doing the actual work
const doTheThing = async () => {
  await fetch(firstApiCall); // kick off the process
  try {
    // wait for completion
    const data = await poll(url, {}, 5000, 6); // ~30sec timeout

    // pass successful result onwards
    return onSuccess(data);
  } catch (err) {
    // Error bubbling is a little weird with async
    // functions, so we'll just handle it here and
    // return undefined
    console.error(err)
    return
  }
};

推荐阅读