在下面的示例中,我模拟了一个用户可以触发某些操作的场景,每个操作都是一个异步操作(包装在 promise 中(,可以通过随机计时解决。
操作列表也是动态的,用户在一段时间内只能触发一个或多个操作。
我需要:
- 保持承诺决议的顺序,同时考虑到事先不知道完整的操作列表。
我可以使用 ES6 和浏览器原生承诺
若要测试该示例,请单击多次(可变频率(按钮。
(function (window) {
document.addEventListener('DOMContentLoaded', e => {
let logActionsElm = document.getElementById('logActions');
let logOperationsElm = document.getElementById('logOperations');
let logCounterElm = document.getElementById('logCounter');
let btnActionElm = document.getElementById('btnAction');
let actionCounter = 0;
let operationDurations = [1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000];
let getRandomNumber = (min, max) => Math.floor(Math.random() * (max - 0 + min)) + min;
let getRandomOperationDuration = x => operationDurations[getRandomNumber(0, 8)];
let promises = [];
let createAction = (id, duration) => {
logActionsElm.innerHTML += `${id} action_start_duration: ${duration} --------- ${id}<br>`;
let promiseAction = new Promise((resolve, reject) => {
setTimeout(e => {
logActionsElm.innerHTML += `${id} action_end___duration: ${duration} --------- ${id}<br>`;
}, duration);
});
};
let createOperation = x => {
actionCounter++;
let duration = getRandomOperationDuration() / 10;
createAction(actionCounter, duration);
//logActionsElm.innerHTML += `action ${actionCounter} created will resolve after ${duration}<br>`;
};
btnActionElm.addEventListener('click', e => {
createOperation();
});
var counter = 0;
setInterval(x => {
if (counter >= 20) {
return;
}
counter++;
logCounterElm.innerHTML += `${counter} second <br>`;
}, 1000);
});
})(window);
body {
font-size: 1.5em;
font-family: 'Courier New';
}
#logCounter {
position: fixed;
top: 0;
right: 0;
margin: 2em;
}
<button id="btnAction">Triger and action</button>
<div id="logActions"></div>
<div id="logOperations"></div>
<div id="logCounter"></div>
您可以将新的操作函数附加到单个承诺,以确保在解决所有先前的操作之前不会评估操作:
let queue = Promise.resolve();
let userActionIdCounter = 0;
function queueAction(fn) {
queue = queue.then(fn);
return queue;
}
function userAction() {
return new Promise((resolve) => {
const seconds = Math.ceil(Math.random() * 5);
const actionId = userActionIdCounter;
userActionIdCounter += 1;
console.log('User action', userActionIdCounter, 'started');
setTimeout(() => {
console.log('User action', userActionIdCounter, 'complete');
resolve();
}, seconds * 1000);
});
}
document.getElementById('action').addEventListener('click', () => {
queueAction(userAction);
});
<button id='action'>Trigger action</button>
您不应该创建自己的解决方案。 相反,请从此处的大约 158 个现有解决方案中选择一种 https://www.npmjs.com/search?q=promise+queue