[英]JavaScript : updating DOM in loop with Promise
这已经困扰了我几个星期了。 我有一些 Javascript 的工作示例,它在循环中更新 DOM。
但是我无法让这个“技巧”适用于我的真实代码。
这是我的 Plunk 的链接: https ://plnkr.co/edit/oRf6ES74TJatPRetZEec ? p = preview
HTML:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css">
<link rel="stylesheet" href="style.css">
<script src="http://code.jquery.com/jquery-1.12.4.js"></script>
<script src="http://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="js/script.js"></script>
<script src="js/script2.js"></script>
<script src="js/json-util.js"></script>
<script src="js/scorito-dal.js"></script>
<script src="js/matching.js"></script>
</head>
<body>
<div id="log">..log here..</div>
<button onclick="doHeavyJob();">do heavy job</button>
<button onclick="doHeavyJobJquery();">do heavy job with jQuery</button>
<button onclick="match();">match</button>
</body>
</html>
js/script.js 中的脚本,从“做繁重的工作”按钮调用的工作:
async function doHeavyJob() {
$('#log').html('');
for (var j=0; j<10; j++) {
await sleep(1000)
console.log('Iteration: ' + j);
(function (j) {
setTimeout(function() { // pause the loop, and update the DOM
var logPanel = document.getElementById('log');
var txt = 'DOM update' + j;
logPanel.innerHTML += txt + ', ';
}, 0);
})(j);
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
完全相同的代码在 jQuery each() 中不起作用,这似乎是由于 jQuery,并且可以通过使用 for 循环轻松解决。 如果您有兴趣,请查看我的 plunk 中的 script2.js。
我在 js/matching 中的真实脚本(从“匹配”按钮调用)不起作用。
var _keeperCombinations = [];
var _defenderCombinations = [];
var _midfielderCombinations = [];
var _attackerCombinations = [];
var _mostPoints = 0;
var _bestCombination = [];
function updateStatus(keeperCount, ixKeeper, msg) {
msg = '%gereed: ' + Math.round(ixKeeper / keeperCount * 100, 0);
console.log(msg);
$('#log').html(msg);
}
function match() {
$('#log').html('');
updateStatus(1, 1, 'Match started');
var playersData = scoritoDal.getPlayersData();
this.determineKeepers(playersData);
this.determineDefenders(playersData);
this.determineMidfielders(playersData);
this.determineAttackers(playersData);
var keeperCount = _keeperCombinations.length
for (var ixKeeper=0; ixKeeper<keeperCount; ixKeeper++) {
var keepers = _keeperCombinations[ixKeeper];
doMatching(keepers, keeperCount, ixKeeper);
}
if (_bestCombination.length === 0) {
alert('Er kon geen beste combinatie worden bepaald');
}
else {
alert('Ready: ' + _bestCombination.toString());
$(_bestCombination).each(function(ix, playerId) {
});
}
}
/*
* Match 2 keepers, 5 defenders, 6 midfielders and 5 attackers
* First pick the 5 best keepers, 10 best defenders, 12 best midfielders and 10 best attackers.
* 3 / 2 (k), 7 / 3 (d & a) and 8 / 4 (m) >> most points / most points per prices
*/
var _confirmed = false;
function doMatching(keepers, keeperCount, ixKeeper) {
// Make a new promise
let p = new Promise(
// The executor function is called with the ability to resolve or reject the promise
(resolve, reject) => {
for (var ixDefenders=0; ixDefenders<_defenderCombinations.length; ixDefenders++) {
var defenders = _defenderCombinations[ixDefenders];
for (var ixMidfielders=0; ixMidfielders<_midfielderCombinations.length; ixMidfielders++) {
var midfielders = _midfielderCombinations[ixMidfielders];
for (var ixAttackers=0; ixAttackers<_attackerCombinations.length; ixAttackers++) {
var attackers = _attackerCombinations[ixAttackers];
procesPlayers(keepers, defenders, midfielders, attackers);
}
}
resolve(ixDefenders);
}
});
p.then(
function(ixDefenders){
console.log('LOG: ' + keeperCount + " - " + ixKeeper);
updateStatus(keeperCount, ixKeeper);
}
);
}
async function procesPlayers(keepers, defenders, midfielders, attackers) {
var totals = calculateTotals(keepers, defenders, midfielders, attackers);
// check if total price is within budget
if (totals.TotalPrice <= 56500000) {
if (totals.TotalPoints > _mostPoints) {
_mostPoints = totals.TotalPoints;
setBestCombination(keepers, defenders, midfielders, attackers);
}
}
}
function calculateTotals(keepers, defenders, midfielders, attackers) {
var playerIds = [];
var totalPoints = 0;
var totalPrice = 0;
var allPlayers = keepers.concat(defenders, midfielders, attackers);
var checkTeams = [];
$(allPlayers).each(function(ix, player){
var club = checkTeams.find(t => t.Name === player.Club);
if (!club) {
club = {"Name":player.Club, "Count":1};
checkTeams.push(club);
}
else club.Count++;
if (club.Count > 4) {
totalPoints = 0;
return false;
}
playerIds.push(player.ID);
var factor = 1;
if (player.Position === 'Keeper' && ix > 0) factor = 0.5; // 2nd keeper gets less points
if (player.Position === 'Defender' && ix > 2) factor = 0.5; // 4th defender gets less points
if (player.Position === 'Midfielder' && ix > 3) factor = 0.5; // 5th midfielder gets less points
if (player.Position === 'Attacker' && ix > 2) factor = 0.5; // 4th attacker gets less points
var playerPoints = player.Points * factor;
totalPoints += playerPoints;
totalPrice += player.Price;
});
return {"TotalPoints":totalPoints,"TotalPrice":totalPrice};
}
function determineKeepers(playersData) {
console.log('Determining keepers');
$('#progres').text('Determine 5 best keepers');
var bestKeepers = this.determineBestPlayers(playersData, 'Keeper', 3, 2); // 3, 2
if (bestKeepers && $(bestKeepers).length > 0) {
// now determine all combinations
this.determineCombinations(bestKeepers, 2);
_keeperCombinations = this._combinations;
}
}
function determineDefenders(playersData) {
console.log('Determining defenders');
$('#progres').text('Determining 10 best defenders');
var bestDefenders = this.determineBestPlayers(playersData, 'Defender', 5, 3); // 6, 3
if (bestDefenders && $(bestDefenders).length > 0) {
// now determine all combinations
this.determineCombinations(bestDefenders, 5);
_defenderCombinations = this._combinations;
}
}
function determineMidfielders(playersData) {
console.log('Determining midfielders');
$('#progres').text('Determine 12 best midfielders');
var bestMidfielders = this.determineBestPlayers(playersData, 'Midfielder', 5, 3); // 7, 3
if (bestMidfielders && $(bestMidfielders).length > 0) {
// now determine all combinations
console.log('*** Determining all midfielder combinations ***');
this.determineCombinations(bestMidfielders, 6);
_midfielderCombinations = this._combinations;
}
}
function determineAttackers(playersData) {
console.log('Determining attackers');
$('#progres').text('Determine 10 best attackers');
var bestAttackers = this.determineBestPlayers(playersData, 'Attacker', 5, 3); // 6, 3
if (bestAttackers && $(bestAttackers).length > 0) {
// now determine all combinations
this.determineCombinations(bestAttackers, 5);
_attackerCombinations = this._combinations;
}
}
/*
* Determine the best players for a position
* - position: Keeper|Defender|Midfielder|Attacker
* - byPoints: the nr of best players by points
* - byFactor: the nr of best players by factor
*/
function determineBestPlayers(playersData, position, byPoints, byFactor) {
var players = $.grep(playersData, function(p) {return p.Position === position});
var playersByPoints = players.sort(jsonUtil.sortByProperty('Points', true));
var bestPlayersByPoints = playersByPoints.slice(0, byPoints);
var playersByFactor = players.sort(jsonUtil.sortByProperty('Factor', true));
var bestPlayersByFactor = playersByFactor.slice(0, byFactor);
// players could be in both lists, make it unique
var bestPlayers = jsonUtil.joinArrays(bestPlayersByPoints, bestPlayersByFactor, true, 'ID');
// if not the nr wanted, add extra players
// take theze by turn on points / on factor
var cnt = $(bestPlayers).length;
var nextByPoints = true;
var cntExtra = 0;
while (cnt < byPoints + byFactor) {
cntExtra++;
var isOK = false;
while (!isOK) {
var ix=0; // if the next player is already chosen, move to the next
var extraPlayer = {};
if (nextByPoints) {
extraPlayer = playersByPoints[byPoints+cntExtra+ix-1];
}
else {
extraPlayer = playersByFactor[byFactor+cntExtra+ix-1];
}
if (!bestPlayers.find(x => x.ID === extraPlayer.ID)) {
bestPlayers.push(extraPlayer);
isOK = true;
}
else {
ix++;
}
}
nextByPoints = !nextByPoints;
cnt++;
}
bestPlayers = bestPlayers.sort(jsonUtil.sortByProperty('Points', true)); // add the end we want the players sorted by total points
console.log('Best player for position ' + position);
console.log(bestPlayersToString(bestPlayers));
return bestPlayers;
}
function bestPlayersToString(bestPlayers) {
var result = '';
var sep = '';
$(bestPlayers).each(function(ix, player) {
result += sep;
result += JSON.stringify(player);
if (sep === '') sep = ',';
});
return result;
}
function setBestCombination(keepers, defenders, midfielders, attackers) {
_bestCombination = [];
$(keepers).each(function(ix, keeper){
_bestCombination.push(keeper.ID);
});
$(defenders).each(function(ix, defender){
_bestCombination.push(defender.ID);
});
$(midfielders).each(function(ix, midfielder){
_bestCombination.push(midfielder.ID);
});
$(attackers).each(function(ix, attacker){
_bestCombination.push(attacker.ID);
});
}
/* Combinations */
var _combinations = [];
var _curCombination = [];
function determineCombinations(players, cnt) {
_combinations = [];
_curCombination = [];
this.addCombinations(players, cnt);
}
/*
* Take 2 from 5 (keepers), 5 from 10 (defenders, attackera) or 6 from 12 (midfielders)
* It is a rather complex recursive method with nested iterations over the
* (remaining players).
*/
var _curLevel = 1;
function addCombinations(players, cnt) {
for (var i=0; i<players.length; i++) {
var player = players[i];
_curCombination.push(player);
if (_curCombination.length == cnt) {
_combinations.push(_curCombination.slice(0)); // slicing creates a clone
//console.log(curCombinationToString());
_curCombination.pop();
continue;
}
var curPlayers = players.slice(i+1);
_curLevel++;
addCombinations(curPlayers, cnt);
};
_curCombination.pop();
_curLevel--;
}
function curCombinationToString() {
var result = '';
var sep = '';
$(_curCombination).each(function(ix, player) {
result += sep;
result += JSON.stringify(player);
if (sep === '') sep = ',';
});
return result;
}
任何想法将不胜感激!!!!
经过无数次尝试,终于让这个工作起来了。 当然,我想和你分享这个。
这是使其工作的本质:
所以这有效:
'use strict'; async function testPromise() { var msg; for (var ix=1; ix<10; ix++) { msg = 'Before loop #'+ix $('#log').html(msg); await doActualWork(); msg = 'After loop #'+ix $('#log').html(msg); } } /* * Perform logic for one loop */ function doActualWork() { return new Promise( function (resolve, reject) { window.setTimeout( function () { // do the actual work like calling an API resolve(); }, 100); } ); }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.