Можно ли перечислить / убить / ... все ожидающие обещания / asyn c события в безголовом chrome? - PullRequest
2 голосов
/ 16 января 2020

У меня есть куча интеграционных тестов с использованием chrome без головы. Поскольку перезапуск браузера на совершенно новом профиле обходится слишком дорого, проводник пытается «очистить» состояние браузера (flu sh кеши, очистить куки и хранилище, ...) при разрыве.

Однако есть повторяющаяся проблема, которая на этапе очистки устраняет некоторые асинхронные c операции и пытается сделать то, что они делают в бессмысленном состоянии.

Здесь есть две проблемы:

  1. asyn c Поддержка трассировки стека в CDT указана как экспериментальная и вообще не появляется в ответе (возможно, потому, что их нужно как-то включить через скрытый флаг)
  2. Я понятия не имею, на чем все еще работает этот момент, и не может даже отладить то, что ломается из-за (1)

Есть ли способ улучшить ожидаемую ситуацию, просматривая heisenbugs по мере их появления, пытаясь медленно пробиться вверх вызовы asyn c все больше регистрируются, пока не будет найдена причина root

1 Ответ

0 голосов
/ 16 января 2020

Сначала мы делаем ловушку, чтобы иметь возможность захватывать все пакеты xhr. Вам придется выполнить это до того, как загрузятся другие ваши скрипты. Пробали вставили это в ваш скрипт загрузки / подготовки перед запуском тестов.

Я реализовал ниже кнопки запуска и остановки. start делает 300 xhr запросов, просто "нормальным" способом. Если вы нажмете «Стоп», вы можете отменить их все. В идеале вы должны поместить код обработчика события остановки в событие beforeunload .

Если вы не хотите останавливать их, вы можете проанализировать их состояние, запрошенные URL-адреса и т. Д. c ... из одного аккуратного массива, в котором вы отслеживаете все в коде.

Этот пример работает, потому что только «так» много запросов могут быть сделаны одновременно браузером. Остальные в очереди ожидают ожидания, пока слот не освободится. Я использовал 300 запросов, потому что я не знаю большого / медленного источника для запроса, который не защищен CORS, и это дает нам людям достаточно времени, чтобы нажать кнопку остановки (я надеюсь).

function addXMLRequestCallback(callback){
  var oldSend, i;
  if( XMLHttpRequest.callbacks ) {
      // we've already overridden send() so just add the callback
      XMLHttpRequest.callbacks.push( callback );
  } else {
      // create a callback queue
      XMLHttpRequest.callbacks = [callback];
      // store the native send()
      oldSend = XMLHttpRequest.prototype.send;
      // override the native send()
      XMLHttpRequest.prototype.send = function(){
          // process the callback queue
          // the xhr instance is passed into each callback but seems pretty useless
          // you can't tell what its destination is or call abort() without an error
          // so only really good for logging that a request has happened
          // I could be wrong, I hope so...
          // EDIT: I suppose you could override the onreadystatechange handler though
          for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
              XMLHttpRequest.callbacks[i]( this );
          }
          // call the native send()
          oldSend.apply(this, arguments);
      }
  }
}
/**
 * adding some debug data to the XHR objects. Note, don't depend on this, 
 * this is against good practises, ideally you'll have your own wrapper 
 * to deal with xhr objects and meta data.
 * The same way you can extend the XHR object to catch post data etc...
 */
var xhrProto = XMLHttpRequest.prototype,
    origOpen = xhrProto.open;
    origSend = xhrProto.send;
xhrProto.open = function (method, url) {
    this._url = url;
    return origOpen.apply(this, arguments);
};
xhrProto.send = function (data) {
    this._data = data;
    return origSend.apply(this, arguments);
};

+function() {
 var xhrs = [],
     i, 
     statuscount = 0, 
     status = document.getElementById('status'),
     DONE = 4;;
 addXMLRequestCallback((xhr) => {
    xhrs.push(xhr);
 });

 document.getElementById('start').addEventListener('click',(e) => {
    statuscount = 0;
    var data = JSON.stringify({
      'user': 'person',
      'pwd': 'password',
      'organization': 'place',
      'requiredkey': 'key'
    });
    for(var i = 0;i < 300; i++) {
       var oReq = new XMLHttpRequest();
       oReq.addEventListener("load", (e) => {
          statuscount++;
          status.value=statuscount;
       });
       oReq.open("GET", 'https://code.jquery.com/jquery-3.4.1.js');
       
       oReq.send(data);
    }
 });
 
 document.getElementById('cancel').addEventListener('click', (event) => {
     for(i = 0; i < xhrs.length; i++) {
         if(xhrs[i].readyState !== DONE) {
            console.log(xhrs[i]._url, xhrs[i]._data , 'is not done');
         }
         
     }
     /** Cancel everything */
     for(i = 0; i < xhrs.length; i++) {
        if(xhrs[i]) { 
           xhrs[i].abort();
        }
     }
     
 });
}();
<button id="start">start requests</button>
<button id="cancel">cancel requests</button>
<progress id="status" value="0" max="300"></progress>

Код любезности addXMLRequestCallback meouw из этого ответа
Код xhrProto, сохраняющий переменные отладки Джоэл Ричард из этого ответ

...