我正在尝试做一个小例子,其中四个div将依次逐个突出显示。我想用循环和承诺来做,但页面进入无限循环。我的承诺肯定是错的,但我无法理解它应该怎么做。
'user strict';
var divAr = document.getElementsByTagName("div");
console.log(divAr);
var colors = ['blue', 'red', 'yellow', 'green'];
var i = 0;
while (i < divAr.length) {
divAr[i].style.backgroundColor = colors[i];
var promise = new Promise(function(resolve) {
lightenButton(i);
window.setTimeout(function() {
resolve(i);
}, 1500);
})
promise.then(function(i) {
i++;
});
}
function lightenButton(index) {
var oldColor = window.getComputedStyle(divAr[index], null)['background-color'];
var newColor = "";
function setOldColor() {
divAr[index].style.backgroundColor = oldColor;
}
switch (oldColor) {
case "rgb(0, 0, 255)":
newColor = "#9999ff";
break;
case "rgb(255, 0, 0)":
newColor = "#ff9999";
break;
case "rgb(255, 255, 0)":
newColor = "#ffffcc";
break;
case "rgb(0, 128, 0)":
newColor = "#99ff99";
break;
}
divAr[index].style.backgroundColor = newColor;
setTimeout(setOldColor, 500);
}
body {
background-color: Grey;
}
div {
width: 80px;
height: 55px;
border: 1px dotted grey;
margin: 10px;
float: left;
text-align: center;
line-height: 50px;
}
<div id="1">1</div>
<div id="2">2</div>
<div id="3">3</div>
<div id="4">4</div>
答案 0 :(得分:3)
这可能是您正在寻找的。它几乎不需要解释,因为async
/ await
使您的代码变得简单愚蠢。显然,是的,您需要transpile您的JavaScript才能在大多数浏览器中使用它。
const wait = ms => new Promise(r => setTimeout(r, ms));
async function loop (elems, i) {
elems[i].classList.add('highlight');
await wait(1000);
elems[i].classList.remove('highlight');
await wait(1000);
return await loop(elems, (i + 1) % elems.length);
}
loop(document.querySelectorAll('div'), 0);
这是一个在浏览器中有效的转换版本。展开代码段,看看它是否有效:)
'use strict';
var loop = function () {
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(elems, i) {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
elems[i].classList.add('highlight');
_context.next = 3;
return wait(1000);
case 3:
elems[i].classList.remove('highlight');
_context.next = 6;
return wait(1000);
case 6:
_context.next = 8;
return loop(elems, (i + 1) % elems.length);
case 8:
return _context.abrupt('return', _context.sent);
case 9:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
return function loop(_x, _x2) {
return _ref.apply(this, arguments);
};
}();
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
var wait = function wait(ms) {
return new Promise(function (r) {
return setTimeout(r, ms);
});
};
loop(document.querySelectorAll('.panel'), 0);
&#13;
body {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: center;
}
.panel {
width: 3rem;
background-color: #eee;
text-align: center;
padding: 0.5rem 1rem;
transition: background-color 0.5s ease;
}
.highlight {
background-color: dodgerblue;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.16.0/polyfill.js"></script>
<div class="panel">1</div>
<div class="panel">2</div>
<div class="panel">3</div>
<div class="panel">4</div>
&#13;
答案 1 :(得分:1)
你可以这样做:
var divs = [].slice.call(divAr, 0);
divs.reduce(function(promise, div, index) {
return promise.then(function() {
lightenButton(index);
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 1500);
});
});
}, Promise.resolve());
那么,它是如何运作的?让我们首先了解我们需要构建的承诺链:
startpromise.then(lightenButtonIndex1).then(lightenButtonIndex2).then(...
Reduce迭代一个元素数组并返回前一个函数执行的结果。正如您在上面所示的链中所看到的,我们需要在每次迭代时返回promise,以便我们可以使用then
方法将函数附加到它,然后再次为下一次迭代返回promise。这正是代码正在做的事情。因此,我们从代码中使用startpromise
创建的Promise.resolve()
开始。然后迭代:
迭代1
params (startpromise, div1, index=0)
添加回调并返回承诺
var lightenButtonIndex1Promise = startpromise.then(lightenButtonIndex1);
return lightenButtonIndex1Promise;
迭代2
params (lightenButtonIndex1Promise, div2, index=1)
添加回调并返回承诺
var lightenButtonIndex2Promise = lightenButtonIndex1Promise .then(lightenButtonIndex2);
return lightenButtonIndex2Promise;
所以它与迭代4的方式相同。
这是没有reduce
的版本,但对我来说看起来很麻烦:
var promise = Promise.resolve();
for (var i=0; i< divs.length; i++) {
promise = promise.then((function(index) {
return function() {
lightenButton(index);
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 1500);
});
}
})(i));
}
以下是工作示例,我修改了您的lightenButton
函数进行演示:
document.addEventListener('DOMContentLoaded', function () {
var divAr = document.getElementsByTagName("div");
var divs = [].slice.call(divAr, 0);
divs.reduce(function (promise, div, index) {
return promise.then(function () {
lightenButton(index);
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, 1500);
});
});
}, Promise.resolve());
function lightenButton(index) {
divs.forEach(function (div, i) {
if (index === i) {
divAr[i].style.backgroundColor = "blue";
} else {
divAr[i].style.backgroundColor = "";
}
});
}
});
body {
background-color: Grey;
}
div {
width: 80px;
height: 55px;
border: 1px dotted grey;
margin: 10px;
float: left;
text-align: center;
line-height: 50px;
}
<div id="1">1</div>
<div id="2">2</div>
<div id="3">3</div>
<div id="4">4</div>