【问题标题】:javascript promise chains not waiting for previous promise to executejavascript 承诺链不等待先前的承诺执行
【发布时间】:2018-03-10 08:38:29
【问题描述】:

我很难理解 javascript 承诺。我有一个简单的列表,我想通过添加一个“活动”类来依次突出显示每个元素,每个元素之间有一个暂停。

所以我有以下标记 -

<h2 class="step step1">Promise</h2>
<h2 class="step step2">Promise</h2>
<h2 class="step step3">Promise</h2>
<h2 class="step step4">Promise</h2>

和 2 个 javascript 承诺。先设置步-

function setStep(step) {
    return new Promise(function (resolve, reject) {
        console.log("Step ", step, new Date())
        document.querySelectorAll('.step').forEach(function (match) {
            match.classList.remove("active");
        });

        document.querySelector(".step" + step).classList.add("active");
        resolve(step);
    })
}

第二个实现等待 -

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

然后我试图像这样将它们链接在一起 -

wait(1000)
    .then(function () { setStep(1) })
    .then(wait(1000))
    .then(function () { setStep(2) })
    .then(wait(1000))
    .then(function () { setStep(3) })

第一次等待似乎按预期执行,但其他所有事情似乎都一起发生,第 3 步被突出显示,中间没有等待。控制台消息都显示相同的时间戳。

我忽略了什么?

完整代码如下-

<style>
    .active {
        background-color: #C00;
        color: #FFF;
    }
</style>

<h2 class="step step1">Step 1</h2>
<h2 class="step step2">Step 2</h2>
<h2 class="step step3">Step 3</h2>

<script>
  const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

  function setStep(step) {
    return new Promise(function (resolve, reject) {
        console.log("Step ", step, new Date())
        document.querySelectorAll('.step').forEach(function (match) {
            match.classList.remove("active");
        });

        document.querySelector(".step" + step).classList.add("active");
        resolve(step);
    })
}

  wait(1000)
    .then(function () { setStep(1) })
    .then(wait(1000))
    .then(function () { setStep(2) })
    .then(wait(1000))
    .then(function () { setStep(3) })
</script>

【问题讨论】:

    标签: javascript promise


    【解决方案1】:

    您需要将函数引用传递给.then(),而不是承诺。所以改变这个:

    .then(wait(1000))
    

    到这里:

    .then(wait.bind(null, 1000))
    

    或者这个:

    .then(() => wait(1000))
    

    .then() 仅在您向其传递稍后可以调用的函数引用时才能正常工作。当您执行.then(wait(1000)) 时,您将立即执行wait(1000) 并将返回值(一个承诺)传递给.then().then() 不是这样工作的,您也不想立即执行 wait(1000)


    或者,您可以创建一个新的waitFn(),它返回一个可以按照您的方式使用的函数(因为它在调用时返回一个函数):

    function waitFn(t) {
        return function() { return wait(t);}
    }
    

    那么,你可以这样做:

    wait(1000)
      .then(function () { setStep(1) })
      .then(waitFn(1000))
      .then(function () { setStep(2) })
      .then(waitFn(1000))
    .  then(function () { setStep(3) })
    

    【讨论】:

    • 成功了。是否可以将等待函数重写为单个函数,让我可以像原来一样使用它?
    • @benophobia - 不,这是不可能的。要像fn(1000).then(...) 那样启动一个承诺链,它必须返回一个承诺。要用作p.then(fn(1000)),它必须返回一个函数。一个函数不能两者兼有,除非它在不同的情况下返回不同的类型,这可能不是好的设计。这就是为什么我提供了两个单独的函数来涵盖这两种情况。
    猜你喜欢
    • 1970-01-01
    • 2020-10-31
    • 2018-08-27
    • 2018-10-17
    • 2019-04-29
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 2013-09-16
    相关资源
    最近更新 更多