我已经举了一个例子来展示我的目标:
function onInput(ev) {
let term = ev.target.value;
console.log(`searching for "${term}"`);
getSearchResults(term).then(results => {
console.log(`results for "${term}"`,results);
});
}
function getSearchResults(term) {
return new Promise((resolve,reject) => {
let timeout = getRandomIntInclusive(100,2000);
setTimeout(() => {
resolve([term.toLowerCase(), term.toUpperCase()]);
}, timeout);
});
}
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}

<input onInput="onInput(event)">
&#13;
输入&#34;搜索&#34;盒子,看着控制台。搜索结果不按顺序返回!
如果有新的输入并保证结果按顺序返回,我们如何取消任何待处理的承诺?
答案 0 :(得分:3)
我没有使用去抖或超时,而是使用引用函数在此函数内部设置少量状态在之外(由Jaromanda X建议)。这样,您只需将函数引用更改为noop
之类的内容即可。承诺仍然有效,但不会采取任何行动。但是,最后一个不会更改其功能参考:
var onInput = function() {
let logger = function(term, results) {
console.log(`results for "${term}"`, results);
};
let noop = Function.prototype;
let lastInstance = null;
function ActionManager(action) {
this.action = action;
}
return function onInput(ev) {
let term = ev.target.value;
console.log(`searching for "${term}"`);
if (lastInstance) {
lastInstance.action = noop;
}
let inst = new ActionManager(logger.bind(null, term));
lastInstance = inst;
getSearchResults(term).then(response => inst.action(response));
}
}();
/****************************************
* The rest of the JavaScript is included only for simulation purposes
****************************************/
function getSearchResults(term) {
return new Promise((resolve, reject) => {
let timeout = getRandomIntInclusive(100, 2000);
setTimeout(() => {
resolve([term.toLowerCase(), term.toUpperCase()]);
}, timeout);
});
}
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
<input onInput="onInput(event)">
答案 1 :(得分:3)
您可以使用Promise.race
取消上一个链的效果:
let cancel = () => {};
function onInput(ev) {
let term = ev.target.value;
console.log(`searching for "${term}"`);
cancel();
let p = new Promise(resolve => cancel = resolve);
Promise.race([p, getSearchResults(term)]).then(results => {
if (results) {
console.log(`results for "${term}"`,results);
}
});
}
function getSearchResults(term) {
return new Promise(resolve => {
let timeout = 100 + Math.floor(Math.random() * 1900);
setTimeout(() => resolve([term.toLowerCase(), term.toUpperCase()]), timeout);
});
}
<input onInput="onInput(event)">
我们这样做是通过注入undefined
结果并对其进行测试来实现的。
答案 2 :(得分:1)
一个可行的解决方案是包含firstf
并简单地忽略任何早期时间戳(因而过时)的响应。
latestTimestamp
let latestTimestamp = 0;
function onInput(ev) {
let term = ev.target.value;
console.log(`searching for "${term}"`);
latestTimestamp = Date.now();
getSearchResults(term, latestTimestamp).then(results => {
if (results[2] !== latestTimestamp) {
console.log("Ignoring old answer");
} else {
console.log(`results for "${term}"`, results);
}
});
}
function getSearchResults(term, latestTimestamp) {
return new Promise((resolve, reject) => {
let timeout = getRandomIntInclusive(100, 2000);
setTimeout(() => {
resolve([term.toLowerCase(), term.toUpperCase(), latestTimestamp]);
}, timeout);
});
}
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
答案 3 :(得分:-1)
您可以使用async
包 - 一堆实用程序来维护异步代码。它最初是为node.js开发的,但它也可以用在前端
您需要series
功能,它会保存承诺的顺序。以下是coffeescript中的一个简短示例:
async.series([
->
### do some stuff ###
Q 'one'
->
### do some more stuff ... ###
Q 'two'
]).then (results) ->
### results is now equal to ['one', 'two'] ###
doStuff()
.done()
### an example using an object instead of an array ###
async.series({
one: -> Q.delay(200).thenResolve(1)
two: -> Q.delay(100).thenResolve(2)
}).then (results) ->
### results is now equal to: {one: 1, two: 2} ###
doStuff()
.done()
见caolan.github.io/async /
答案 4 :(得分:-2)
你不应该像你所做的那样在承诺中使用setTimeout
,因为从.then
你要回复来自.setTimeout()
的回调,这将无法正常工作和混乱订单。为了使承诺顺利进行,您应该创建如下所示的函数:
function wait(n){
return new Promise(function(resolve){
setTimeout(resolve, n)
});
}
并使用该函数替换setTimeout()
,如下所示:
wait(getRandomIntInclusive(100,2000)).then(function(){
// code
});