简体   繁体   English

如何在另一个异步函数内调用 setTimeout 内的异步函数?

[英]How to call an async function inside setTimeout, inside another Async function?

I made a redux action to play a song using the Spotify player's API.我做了一个 redux 动作来使用 Spotify 播放器的 API 播放一首歌。 I want to pause the song after a certain amount of time and so I set a timeout inside the async function to call another async function after the timeout ends.我想在一段时间后暂停这首歌,所以我在 async 函数中设置了一个超时,以便在超时结束后调用另一个异步函数。 However every time I call the first play function the timeout for the second async function seems to grow for apparently no reason.然而,每次我调用第一个播放函数时,第二个异步函数的超时似乎无缘无故地增长。 My code:我的代码:

let timeoutId

...

export const playElement = (accessToken, songUri, refreshToken, start, duration, deviceId) => async (dispatch) => {
  dispatch(loading());
  clearTimeout(timeoutId)
  timeoutId = setTimeout(async () => {
    await dispatch(pausePlayer(accessToken, refreshToken, deviceId, songUri))
    
  }, duration*1000)

 
  try { 
    const url = deviceId === '' ? '/me/player/play' : `/me/player/play?device_id=${deviceId}`;
    await spotify.put(
      url,
      { position_ms: start * 1000, uris: [songUri] },

      {
        headers: {
          Authorization: `Bearer ${accessToken}`,
          Accept: 'application/json',
          'Content-Type': 'application/json',
        },
      }
    );
    
    dispatch({
      type: PLAY,
      playing: true,
    })
  } catch (error) {
    dispatch(returnErrors(error));
    if (error.response.status === 401) {
      const newAccessToken = await dispatch(refreshAccessToken(refreshToken));
      dispatch(playElement(newAccessToken, songUri, refreshToken, start, duration, deviceId));
    }
    if (error.response.status === 404) {
      const newDeviceId = await dispatch(getDeviceId(accessToken));
      dispatch(playElement(accessToken, songUri, refreshToken, start, duration, newDeviceId));
    }
  }
  
  dispatch(notLoading());

};

export const pausePlayer = (accessToken, refreshToken, deviceId, songUri) =>  async (dispatch, getState) => {
  try { 
    let state = getState();
    const url = deviceId === '' ? '/me/player/pause' : `/me/player/pause?device_id=${deviceId}`;
    if (state.spotifyPlayer.playing && state.spotifyPlayer.controlledPlay && state.spotifyPlayer.song === songUri) { 
      await spotify.put( 
        url,
        {}, {
          headers: {
            Authorization: `Bearer ${accessToken}`,
          },
        }
      )
  }
    dispatch({
      type: PAUSE,
      payload: false
    })

    } catch (error) {
      dispatch(returnErrors(error));
      if (error.response.status === 401) {
        const newAccessToken = await dispatch(refreshAccessToken(refreshToken));
        dispatch(pausePlayer(newAccessToken, deviceId));
      }
      if (error.response.status === 404) {
        const newDeviceId = await dispatch(getDeviceId(accessToken));
        dispatch(pausePlayer(accessToken, newDeviceId));
      }
    }
}

Posting this if someone runs into a similar problem.如果有人遇到类似问题,请发布此信息。 Basically this is the way Javascript works with the main thread since js is a single-threaded language, set timeout will only run the function placed in it at the earliest after the provided delay.基本上这是 Javascript 与主线程一起工作的方式,因为 js 是一种单线程语言,设置超时只会在提供的延迟后最早运行放置在其中的函数。 This is not reliable when it comes to code that needs to be executed exactly at that time.当涉及到需要在当时准确执行的代码时,这是不可靠的。

To get around that you can use web workers which work sort of outside the main thread.为了解决这个问题,您可以使用在主线程之外工作的网络工作者。 I happened to have found a useful npm package that does this already so I'll link it:我碰巧找到了一个有用的 npm 包,它已经这样做了,所以我将链接它:

https://www.npmjs.com/package/worker-timers https://www.npmjs.com/package/worker-timers

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM