在 webdriver.io 的 while 循环中链接承诺

Chaining promises in a while loop in webdriver.io

我想通过捕获视口大小的图块来截取整个网页的屏幕截图。快完成了,但我对 promises 还很陌生,我正在寻找正确的方法。

这是我的代码。问题是对 client.execute(...).then(...) 的调用不会在循环迭代之间等待自身。而最后的'end'也不等待前面的'then',所以被注释掉了。

...
var client = webdriverio.remote(options);
...
client    
  ...
  .then(function() {

    var yTile = 0;
    var heightCaptured = 0;

    while(heightCaptured < documentSize.height) {
      var tileFile  = 'screenshot-' + yTile + '.png';

      client
      .execute(function(heightCaptured) {
        window.scrollTo(0, heightCaptured);
      }, heightCaptured)
      .then(function() {
        console.log('captured: ' + tileFile);
        client.saveScreenshot('./' + tileFile);

        return client;
      });

      heightCaptured += viewportSize.height;
      yTile++;
    }

  })
  //.client.end()
  ;

在这种情况下使用 promise 的正确方法是什么?

谢谢。

您不能使用 while 链接链接不确定数量的异步操作,因为 while 循环将 运行 立即完成,但您需要在每次异步后做出循环决策执行。

相反,您可以创建一个内部函数 next(),它 return 是一个承诺并重复调用它,将每个链接到前一个直到完成,并在循环内决定是否将另一个调用链接到 next() 通过 return 在先前的 .then() 处理程序中对其进行处理,或者您可以通过 return 处理常规值(不是承诺)来结束链。

...
var client = webdriverio.remote(options);
...
client
    ...
    .then(function () {
        var yTile = 0;
        var heightCaptured = 0;

        function next() {
            if (heightCaptured < documentSize.height) {
                var tileFile = 'screenshot-' + yTile + '.png';

                // return promise to chain it automatically to prior promise
                return client.execute(function (heightCaptured) {
                    window.scrollTo(0, heightCaptured);
                }, heightCaptured).then(function () {
                    console.log('captured: ' + tileFile);

                    // increment state variables
                    heightCaptured += viewportSize.height;
                    yTile++;

                    // return this promise to so it is also chained properly
                    // when this is done, call next again in the .then() handler
                    return client.saveScreenshot('./' + tileFile).then(next);
                });

            } else {
                // Done now, end the promise chain by returning a final value
                // Might also consider returning yTile so the caller knows
                // how many screen shots were saved
                return client;
            }
        }
        // start the loop
        return next();
    }).then(function () {
        // done here
    }, function (err) {
        // error here
    });

作为参考,如果您在 .then() 处理程序中并且您 return 来自 .then() 处理程序的承诺,那么该承诺将链接到先前的承诺。如果您 return 取而代之的是一个值,那么 promise 链就到此结束,并且该值被 return 编辑为整个链的最终解析值。

因此,在此示例中,由于 next() return 是一个承诺,您可以从 .then() 处理程序中重复调用 return next();,这将链接所有屏幕截图一起进入一个顺序链,直到你最终 return 一个值,而不是一个承诺,这将结束链。