承诺2在承诺1之前解决

时间:2019-02-08 09:45:15

标签: javascript angular asynchronous promise rxjs

我正在文本字段中进行搜索,当我键入内容时,会说100毫秒后有一个呼叫转到后端。

例如,如果我们搜索“ 5041”并立即搜索“ 50”,然后再次将其设置为“ 5041”,则有3个对后端的调用。

1."5041" -> Promise 1

2."50"   -> Promise 2

3."5041" -> Promise 3

但是,当我在文本字段中只有“ 5041”时,承诺3(Web调用花费200毫秒)在承诺2(Web调用花费500毫秒)之前解决,这使屏幕反映了承诺2(“ 50”)的结果。 / p>

我需要某种方法让用户在文本字段中键入内容,而不会阻止用户,并且只显示最后一次呼叫的结果。

这是可以在角度应用中使用rxjs中的switchMap实现的。但是,我需要一种在香草JS中实现相同效果的方法。

3 个答案:

答案 0 :(得分:4)

首先,您可以将fetchData函数包装到类似fetchLatestSearchResults函数中,该函数记录了进行网络调用的时间从所有结果中返回最新结果网络通话(与从服务器返回的数据无关)

const generateLatestSearchFetch = function(fetchFunc){
  let mostRecentResult = null;
  let mostRecentResultFetchTime = Date.now();

  return (...args) => {

    const myFetchStartTime = Date.now();

    return fetchFunc(...args)
      .then(data => {
        if (myFetchStartTime > mostRecentResultFetchTime) {
          mostRecentResult = data;
          mostRecentResultFetchTime = myFetchStartTime
        }
        return mostRecentResult;  
      });
  }
};

使用喜欢

fetchData = generateLatestSearchFetch(fetchData);
fetchData('10'); // resolves first and returns result for 10
fetchData('102'); // resolves third and returns result for 1024
fetchData('1024'); // resolves second and returns result for 1024

最后,但并非最不重要,请使用debounce more on this优化针对每种类型事件的网络调用次数。

答案 1 :(得分:3)

您需要一个“最后一个”功能:

// takes a function returning a promise and only reports the last resort
function last(fn) { 
  let p;
  return function(...args) {
    let current = fn(); // call the function
    p = current; // mark it as the last call
    return p.then(result => { 
      // ask am I still the last call?
      if (p === current) return result;
      else return new Promise(() => {}); // never resolve
    });
  }
}

let onlyLastSearch = last((name) => fetch('/api?name=' + name));

onlyLastSearch('a'); // will be ignored
onlyLastSearch('b'); // will be ignored
onlyLastSearch('c'); // only relevant result

答案 2 :(得分:2)

您可以为此使用观察者模式。

const createWrapper = (fn) => {
    let counter = 0;
    let lastFetchId = 0;
    const listeners = [];
    return {
        fetch: (str) => {
            let id = ++counter;
            fn(str).then((data) => {
                if(id > lastFetchId) {
                    listeners.forEach(fn => {
                        fn(data);
                    });
                    lastFetchId = id;
                }
            });
        },
        listen: (fn) => {
            listeners.push(fn);
            return () => {
                const index = listeners.indexOf(fn);
                listeners.splice(index, 1);
            };
        }
    }
}

const SearchWrapper = createWrapper(fetchData);

SearchWrapper.fetch('a');
SearchWrapper.fetch('b');
SearchWrapper.fetch('c');

SearchWrapper.listen((data) => {
    console.log(data);
})