2016-03-25 2 views
2

Я хочу сделать снимок экрана полной веб-страницы, захватив плитки размера видового экрана. Это почти сделано, но я очень новичок в обещаниях, и я ищу правильный способ сделать.Цепочные обещания в цикле while в webdriver.io

Вот мой код. Проблема заключается в вызове client.execute (...). 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() 
    ; 

Каков правильный способ использования обещаний в этом случае?

Спасибо.

ответ

5

Вы не можете использовать while, чтобы связать неопределенное число операций async, потому что цикл while будет запущен до завершения немедленно, но вам необходимо принять решения цикла после каждого выполнения асинхронного вызова.

Вместо этого, вы можете создать внутреннюю функцию next(), которая возвращает обещание и называть его неоднократно, сцепление друг с предыдущим, пока не сделано и принятия решения в цикле ли цепь другой вызов next(), возвращая его внутрь предыдущего .then() обработчика или вы можете закончить цепочку, просто вернув регулярное значение (а не обещание).

... 
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() обработчика и вы возвращаете обещание от .then() обработчика, то, что обещание получает прикован на предыдущее обещание. Если вы вернете значение вместо этого, то цепочка обещаний заканчивается там, и значение возвращается как окончательное разрешенное значение всей цепочки.

Таким образом, в этом примере, поскольку next() возвращает обещание, вы можете повторно позвонить return next(); внутри .then() обработчика и это цепи все ваши скриншоты вместе в одну последовательную цепь, пока, наконец, просто возвращает значение, а не обещание и что закончит цепь.