setTimeout问题后的异步回调执行

时间:2019-01-31 15:09:27

标签: javascript reactjs asynchronous async-await es6-promise

在我的react应用程序中,我有一个函数在某种程度上模拟了对API的调用。有没有办法可以在此API请求之后同步运行回调函数,以使我的数据按发送顺序返回?

// the order in the array here matters
  const wordTypeArr = ['type1', 'type2', 'type3']

// loop sequentially through array
  wordTypeArr.forEach((v,i) => {
        getRandomWordFromAPI(v, addWord)
    })

//simulated "API" - can't modify this function
  const getRandomWordFromAPI = (type, callback) => {
    return setTimeout(function() {
      callback(
        type in dictionary ?
        sample(dictionary[type]) :
        null
      );
    }, (Math.random() * 750 + 250));
  }


//callback runs after response - update the state
  const addWord = (val) =>  {
    const newState = wordList
    newState.push(val)
    setWordList(newState);
}

如您所见,getRandomWordFromAPI函数返回一个超时函数,然后在超时后异步(无序)执行回调。这是不可取的,因为我的结果必须井然有序。

也许我需要将addWord包装在一个诺言中?或类似的东西?

2 个答案:

答案 0 :(得分:2)

更改该功能确实是首选,因为它将使代码更易于阅读。但是由于可以向getRandomWordFromAPI发送回调,所以可以将resolve函数作为回调而不是addWord()发送,然后将addWord链接到解决方案。

由于我们没有字典对象,因此我将代码的某些部分放在注释中,但是结构保持不变。

// the order in the array here matters
const wordTypeArr = ['type1', 'type2', 'type3'];

//simulated "API" - can't modify this function
const getRandomWordFromAPI = (type, callback) => {
  return setTimeout(function() {
    callback( type );
    /*
    callback(
      type in dictionary ?
      sample(dictionary[type]) :
      null
    );*/
  }, (Math.random() * 750 + 250));
}

//callback runs after response - update the state
const addWord = (val) =>  {
  console.log( val );
/*
  const newState = wordList
  newState.push(val)
  setWordList(newState);
*/
  
}

const randomWords = wordTypeArr.map( word => {
  return new Promise(( resolve, reject ) => {
    getRandomWordFromAPI( word, resolve );
  });
});

Promise.all( randomWords ).then( words => words.forEach( addWord ));

答案 1 :(得分:0)

现在是2019年,承诺已经兑现,回调已经结束。更严重的是,这是您如何重构代码以使其按您希望的方式工作的方法:

// mock the API
const getRandomWordFromAPI = (type, callback) => {
  setTimeout(() => {
    let word = `some-word-of-type-${type}`;
    callback(word);
  }, 1000)
}

// promisify the mocked API
const getRandomWordFromAPIPromise = (type) => new Promise(resolve => {
  getRandomWordFromAPI(type, resolve);
});

// fetch all data asynchronously, in order
const wordTypeArr = ['type1', 'type2', 'type3'];
const promises = wordTypeArr.map(getRandomWordFromAPIPromise);
Promise.all(promises).then(words => {
  // do whatever you want with the words
  console.log(words)
});