(承诺循环)_使div一个接一个地突出显示,延迟

时间:2016-11-02 14:45:55

标签: javascript infinite-loop es6-promise

我正在尝试做一个小例子,其中四个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>

2 个答案:

答案 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);

这是一个在浏览器中有效的转换版本。展开代码段,看看它是否有效:)

&#13;
&#13;
'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;
&#13;
&#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>