我认为,承诺是异步的

时间:2017-11-10 23:15:18

标签: javascript asynchronous promise

我一直试图让我的头围绕同步运行的异步代码(或者看起来和感觉就像它一样!)

我希望计数器从上到下依次运行。

在工作中,他们倾向于尝试使用setTimeouts来计时并且不理解回调(我也不理解这一点)但是因为回调链接起来相当复杂(“回调地狱”任何人?)我不是困扰学习它们并且根本不关心遗留浏览器版本。

Please take a look at my fiddle你会看到什么意思。

function runPercentCounter(ind) {

  return new Promise(function(resolve, reject) {

    var argsArray = [{
        display: '#countPercentage1 > span',
        finalVal: 90,
        tickSpeed: 20,
        fillBar: '#fillBar1',
        nextIndex: 1
      },
      {
        display: '#countPercentage2 > span',
        finalVal: 17,
        tickSpeed: 150,
        fillBar: '#fillBar2',
        nextIndex: 2
      },
      {
        display: '#countPercentage3 > span',
        finalVal: 37,
        tickSpeed: 10,
        fillBar: '#fillBar3',
        nextIndex: 'undefined'
      },
    ];

    var args = argsArray[ind]

    var fillBar = $(args.fillBar);
    var display = $(args.display);
    var currentValue = parseInt(display.text());
    $(fillBar).css('width', currentValue + '%');

    var finalVal = args.finalVal;
    var diff = finalVal - currentValue;
    var step = (0 < diff ? 1 : -1);

    for (var i = 0; i < Math.abs(diff); ++i) {
      setTimeout(function() {
        currentValue += step;
        $(fillBar).css('width', (currentValue - step) + '%');
        display.text(currentValue);
      }, args.tickSpeed * i);
      console.log(i);
    }

    var t = args.nextIndex;
    console.log(t);
    if (typeof t != "undefined") {
      resolve(t);

    } else {
      reject('End of the line!');
    }
  });
}


runPercentCounter(0)
  .then(runPercentCounter)
  .then(runPercentCounter)
  .catch(console.error());

percent bars

2 个答案:

答案 0 :(得分:1)

你需要等到你的循环完成resolve承诺。 javascript中的异步编程方式是运行整个函数,包括在任何异步内容发生之前解析承诺的部分。因此,您的承诺很快就会得到解决。

你设置的方式使得添加一个干净的简单修复有点困难。你可以通过在最后一次循环迭代中添加一个超时设置来实现一个不太干净,但仍然很容易的修复,这将延迟承诺解决,直到每个条完成它之后:

function runPercentCounter(ind) {

return new Promise(function(resolve, reject) {

    var argsArray = [{
        display: '#countPercentage1 > span',
        finalVal: 90,
        tickSpeed: 20,
        fillBar: '#fillBar1',
        nextIndex: 1
    },
    {
        display: '#countPercentage2 > span',
        finalVal: 17,
        tickSpeed: 150,
        fillBar: '#fillBar2',
        nextIndex: 2
    },
    {
        display: '#countPercentage3 > span',
        finalVal: 37,
        tickSpeed: 10,
        fillBar: '#fillBar3',
        nextIndex: 'undefined'
    },
    ];

    var args = argsArray[ind]

    var fillBar = $(args.fillBar);
    var display = $(args.display);
    var currentValue = parseInt(display.text());
    $(fillBar).css('width', currentValue + '%');

    var finalVal = args.finalVal;
    var diff = finalVal - currentValue;
    var step = (0 < diff ? 1 : -1);

    for (var i = 0; i < Math.abs(diff); ++i) {
    setTimeout(function() {
        currentValue += step;
        $(fillBar).css('width', (currentValue - step) + '%');
        display.text(currentValue);
    }, args.tickSpeed * i);
    console.log(i);
    }
    // Wait the full amount before resolving
    setTimeout(function(){
        var t = args.nextIndex;
        console.log(t);
        if (typeof t != "undefined") {
        resolve(t);

        } else {
        reject('End of the line!');
        }
    }, args.tickSpeed * Math.abs(diff))


});
}


runPercentCounter(0)
.then(runPercentCounter)
.then(runPercentCounter)
.catch(console.error());

这是一个更新的小提琴:https://jsfiddle.net/0sggcmfe/

修改

使用setInverval()而不是超时处理这是一种更好的方法。它需要负责跟踪你离开runPercentageCounter的哪个栏,并使承诺模式更有意义:

var argsArray = [{
    display: '#countPercentage1 > span',
    finalVal: 90,
    tickSpeed: 20,
    fillBar: '#fillBar1',
    nextIndex: 1
},
{
    display: '#countPercentage2 > span',
    finalVal: 17,
    tickSpeed: 150,
    fillBar: '#fillBar2',
    nextIndex: 2
},
{
    display: '#countPercentage3 > span',
    finalVal: 37,
    tickSpeed: 10,
    fillBar: '#fillBar3',
    nextIndex: 'undefined'
},
];

function runPercentCounter(args) {
    return new Promise(function(resolve, reject) {
        var fillBar = $(args.fillBar);
        var display = $(args.display);
        var currentValue = parseInt(display.text());
        $(fillBar).css('width', currentValue + '%');

        var finalVal = args.finalVal;
        var diff = finalVal - currentValue;
        var step = (0 < diff ? 1 : -1);

        var count = 0
        var interval = setInterval(() => {
            if (count == Math.abs(diff)){
                clearInterval(interval)
                return resolve()
            }
            currentValue += step;
            $(fillBar).css('width', (currentValue - step) + '%');
            display.text(currentValue); 
            count++
        }, args.tickSpeed)        
    });
    }

argsArray.reduce((a, c) => a.then(() => runPercentCounter(c)), Promise.resolve())

这是一个新的小提琴:https://jsfiddle.net/markm/rx83hacm/1/

答案 1 :(得分:0)

你正在解决你的Promise,而不是在动画循环运行之后,这就是为什么事情似乎并行更新。

您可以在for循环后添加另一个setTimeout函数,然后解析Promise