Как в вебинтерфейсе выводить постоянно результат потока?



  • Здравствуйте.

    Есть функция в BAS, который по API получает 2 значния, умножает их друг на друга и результат в переменную [[RESULT]] сохраняет, потом через метку возвращается в начало скрипта и повторяет все действия, обновляя значение.

    Хочу в вебинтерфейсе, на примере видеоурока по созданию веб интерфейса, сделать кнопку "Start", которая запускает парсинг, постоянно обновляя результат. С выводом результата еще не разобрался, некорректно показывает, но почему-то не обновляет результат, когда вызываю функцию.

    Parse: async function()
                {
                    if(this.IsRunning)
                    {
                        return;
                    }
                    
    
                    var self = this
                    
                    this.Log = []
                    this.Error = ""
                    this.IsRunning = true;
    
                    this.Thread = new BASThread()
                    try
                    {
                        var Log = await this.Thread.RunFunction("Parse",)
                        if(Log)
                            this.Log = Log;
                        else
                        {
                            throw "Empty data"
                        }
                    }catch(e)
                    {
                        this.Error = e
                        setTimeout(function(){
                            self.Error = ""
                        },5000)
                    }
    
                },
                Stop: async function()
                {
                    if(!this.IsRunning)
                    {
                        return;
                    }
    
                    this.Log = []
                    this.Error = ""
                    
                    this.Thread.StopThread()
                    this.IsRunning = false;
                }
    

    Вывожу пока криво в таблицу, но все равно криво не обновляет данные. Подскажите, в чем проблема?

    <div class="ui fluid container" id="Main">
      <h2 class="ui header">
      <i>Titke</i>
      <div class="sub header">Descr</div>
      </h2>
      <button class="ui labeled blue icon button" @click="Parse">
      <i class="play icon"></i>
      Start
      </button>
      <button class="ui labeled red icon button" @click="Stop">
      <i class="pause icon"></i>
      Pause
      </button> 
      <table class="ui selectable inverted table">
      <thead>
        <tr>
          <th>Name</th>
          <th>Status</th>
          <th class="right aligned">Notes</th>
        </tr>
      </thead>
      <tbody>
        <template v-for="item in Log">
            <tr>
              <td>{{item}}</td>
              <td>{{item}}</td>
              <td class="right aligned">{{item}}</td>
            </tr>
        </template>
      </tbody>
    </table>
    </div>
    
    


  • Понял, что я выполняю функцию и получая результат, выполнение ее приостанавливается.

    Выходит, получение результат функции не подходит. Сейчас пытаюсь как-то ловить LOG и выводить, но не понимаю еще как, альтернативный вариант это как-то в веб интерфейса пушить еще значение лога или "Result" или с базы данных.



  • Разобрался, что мне нужно использовать SetInterval, но не могу понять как к этому коду добавить его:

    Parse: async function() {
    
                    var self = this
    
                    this.Thread = new BASThread()
                    try {
                        var Result = await this.Thread.RunFunction("Parse", {})
                        this.ParseResult = Result
                    } catch (e) {
                        this.Error = e
                        setTimeout(function() {
                            self.Error = ""
                        }, 5000)
                    }
    
                },
    

    https://stackoverflow.com/questions/52835981/vuejs-setinterval-method-not-working-properly

    По этим инструкциям везде не рабоатет, кто пробовал через SetInterval задавать цикличность кнопкой? Второй кнопкой хочу останавливать цикл.



  • @Jhon Вы бы в названии темы или в самом посте указали бы, что используете vue js. Да и интерфейс лучше было выложить экспортированный, что бы не спрашивать у вас реализацию помимо метода Parse. Например объявляли ли вы в data переменную Log, и если объявляли, то объявляли как строку или как массив?

    @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    Понял, что я выполняю функцию и получая результат, выполнение ее приостанавливается.

    Выходит, получение результат функции не подходит. Сейчас пытаюсь как-то ловить LOG и выводить, но не понимаю еще как, альтернативный вариант это как-то в веб интерфейса пушить еще значение лога или "Result" или с базы данных.

    Получать данные из потока в интерфейс в процессе работы можно по разному, но лучше всего для этого подходит глобальная переменная.
    Сохранять лог в переменную vue js можно используя обработчик событий api

    Api.SetEventHandler(function (EventType, EventData) 
    

    Но объявлять его нужно в хуке created

    https://habr.com/ru/company/mailru/blog/350962/

    72b3c8fa-3077-4387-a0c4-14c46fdb0e86-изображение.png

    например:

    created() {
      var self = this
    
      /////Обработчик событий api
      Api.SetEventHandler(function (EventType, EventData) {
    
        if(EventType == "log"){
          self.Log.push(EventData["text"])
        }
                    
      }
    }
    

    @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    Разобрался, что мне нужно использовать SetInterval, но не могу понять как к этому коду добавить его:

    Parse: async function() {
    
                    var self = this
    
                    this.Thread = new BASThread()
                    try {
                        var Result = await this.Thread.RunFunction("Parse", {})
                        this.ParseResult = Result
                    } catch (e) {
                        this.Error = e
                        setTimeout(function() {
                            self.Error = ""
                        }, 5000)
                    }
    
                },
    

    Создав поток

    this.Thread = new BASThread()
    

    вы всё равно ждёте завершение выполнения функции

    var Log = await this.Thread.RunFunction("Parse",)
    

    разница с упрощённым запуском функции здесь только в том, что поток не завершается после выполнения функции.

    https://stackoverflow.com/questions/52835981/vuejs-setinterval-method-not-working-properly

    По этим инструкциям везде не рабоатет, кто пробовал через SetInterval задавать цикличность кнопкой? Второй кнопкой хочу останавливать цикл.

    Мне не нравится SetInterval() в асинхронном коде потому что он совершает вызов функции по времени, а не спустя необходимое время после предыдущего выполнения функции. Но если это не критично, то пофиг.

    Для того, что бы остановить SetInterval() вы должны будете записать идентификатор таймера

    this.id = setInterval(testFunction, 3000)
    

    и использовать метод clearTimeout() для отмены

    clearTimeout(self.id)
    


  • @Jhon а вообще лайк за использование vue js, мне нравится этот фреймворк. Интерфейс FingerprintManager написан полностью на нём.



  • @Fox Спасибо за обширный ответ! Да, я уже изучаю жизненный цикл проекта, примерно понял что мне нужно задать в Cretead or Mounted, но к сожалению не работает.

    Прикрепил фронтовый код.

    Code.txt

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

    Сейчас я перешел на такой вариант, что я запускаю функцию, жду ее отработку и получаю return, записываю его в ParseResult, потом обновляется он во фронте. Не могу заставить обновлять функцию (перезапускать) каждые 2с например, но опять же, это не идеальное решение, так как будет постоянное создание и удаление потока, но тем не менее. В идеале задача такая, что запускать "цикл", который бы обновлял данные (сейчас просто в кнопке, как пример), тормозить его кнопкой и снова запускать, уже в функцию передавать надстройки.



  • @Fox Если верно понял, реализовать можно в хуке "Created" отработку переменной Log/Text, но в этом случае мы по сути ловим 1 лог, верно? В идеале мы не можем прям брать [[%NAME%]] из функции и сохранять в дату?



  • @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    @Fox Если верно понял, реализовать можно в хуке "Created" отработку переменной Log/Text, но в этом случае мы по сути ловим 1 лог, верно?

    Нет. Вы знакомы с формулировкой "обработчик событий"?

    В идеале мы не можем прям брать [[%NAME%]] из функции и сохранять в дату?

    Чегось? Вы можете выполнить произвольный js код в интерфейсе через действие "Выполнить яваскрипт в веб интерфейсе", но работать напрямую с vue js из этого действия не получится по объективным причинам. Но передавать данные можно вполне, например через промежуточную переменную



  • @Fox Не знаком, изучаю. Нет ли примера передачи данных через переменную?



  • @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    @Fox Не знаком, изучаю. Нет ли примера передачи данных через переменную?

    Все примеры я беру из головы, вывод данных из неё к сожалению занимает уйму времени :D.

    Думаю для ваших целей идеально подойдёт действие "Результат" и обработчик событий на него в интерфейсе
    https://wiki.bablosoft.com/web-interface/#/gettingscriptstatistics?id=event-result

    created() {
      var self = this
    
      /////Обработчик событий api
      Api.SetEventHandler(function (EventType, EventData) {
    
        if (EventType == "result") {
          var TabNumber = EventData["number"]
          Api.DownloadResult(TabNumber).then((res) => {
            self.Log = res
          })
        }
      }
    }
    


  • Спасибо, а подскажите как теперь этот результат в значение писать?

    Верно я понял, что я могу в HTML указать {{ResultSaver}}, а здесь добавить строку this.ResultSaver = res и в HTML обновится?



  • @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    Спасибо, а подскажите как теперь этот результат в значение писать?

    Верно я понял, что я могу в HTML указать {{ResultSaver}}, а здесь добавить строку this.ResultSaver = res и в HTML обновится?

    Да, благодаря реактивности в html значение изменится сразу же, как поменяется переменная. Это не будет работать если вы будете обновлять свойства объекта или массив по индексу
    https://ru.vuejs.org/v2/guide/reactivity.html



  • @Fox Если мы создаем в "created" обработчик переменной result, то запустик кликом функцию в BAS, которая зациклена в BAS переходом, не выйдет постоянно ловить новое значение?



  • @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    @Fox Если мы создаем в "created" обработчик переменной result, то запустик кликом функцию в BAS, которая зациклена в BAS переходом, не выйдет постоянно ловить новое значение?

    Чегось?



  • @Fox У меня вот такой JS код:

    $(document).ready(function() {
    
    
        var app = new Vue({
            el: '#Main',
            data: {
                Log: [],
                Thread: null,
                ParseResult: "",
                Error: ""
            },
            Mounted() {
                setInterval(() => this.parseres(), 2000);
            },
            methods: {
                Parse: async function(loop)
                {
                    var self = this
                    this.ParseResult = ""
                    this.Thread = new BASThread()
                    var Result = await this.Thread.RunFunction("Parse", {})
                    this.ParseResult = Result
                    setTimeout(function(){
                          Parse(loop);
                       }, loop);
                },
                Stop: async function() {
                    if (!this.IsRunning) {
                        return;
                    }
    
                    this.Log = []
                    this.Error = ""
    
                    this.Thread.StopThread()
                    this.IsRunning = false;
                }
            }
        })
    
        /////Api event handler
        Api.SetEventHandler(function(EventType, EventData) {
    
            /////Script started
            if (EventType == "start") {}
    
            /////Script stopped
            if (EventType == "stop") {}
    
            if (EventType == "log") {
                //Obtain log text
                var LogText = EventData["text"]
                this.ParseResult = LogText
            };
    
            /////More events: https://wiki.bablosoft.com/web-interface/#/managingscriptlifetime
    
        })
    
        /////Automatically start script https://wiki.bablosoft.com/web-interface/#/managingscriptlifetime?id=method-acceptresources
        Api.AcceptResources(true)
    
    
        /////After everything is initialized may show body
        $("body").fadeIn()
    
        /////Events
    
    });
    
    

    Ну и кнопка HTML:

    	<button @click="Parse" class="ui labeled blue icon button">
    		<i class="play icon"></i>
    		Start2
    	</button>
    	<button @click="Stop" class="ui labeled red icon button">
    		<i class="pause icon"></i>
    		Pause
    	</button>
    
    

    Не получается прям никак сделать так, чтобы по кнопке запускало функцию, которая бы постоянно обновляла данные. Хочу потом еще стоп прикрутить, но это уже другая идея. Могу я Вас попросить показать где у меня здесь ошибка?



  • @Fox Добавил как Вы сказали в хуку "created" сохранение лога в значение, но не сохраняем (не меняет значение), подскажите почему?

        var app = new Vue({
            el: '#Main',
            data: {
                Log: [],
                Thread: null,
                ParseResult: "",
                Error: ""
            },
            created() {
                Api.SetEventHandler(function(EventType, EventData) {
    
                /////Script started
                if (EventType == "start") {}
    
                /////Script stopped
                if (EventType == "stop") {}
    
                if (EventType == "log") {
                this.ParseResult = "123"
                ParseResult = "12345"
                console.log("1234")
                };
    


  • @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    @Fox Добавил как Вы сказали в хуку "created" сохранение лога в значение, но не сохраняем (не меняет значение), подскажите почему?

    Я же вам готовый код скидывал, в нём я получал текст лога из данных события self.Log.push(EventData["text"]). А в вашем коде вы записали строку в переменную, почему она должна тогда меняться?

    Так же я выложил готовый код для получения результата из скрипта

    отдельный вопрос на счёт участка кода:

            Mounted() {
                setInterval(() => this.parseres(), 2000);
            },
    

    Зачем вы используете хук Mounted вообще? Я же скидывал статью по хукам:

    В хуке mounted вы получите полный доступ к реактивному компоненту, шаблонам и отрисованному DOM (через this.$el). Mounted — самый популярный хук жизненного цикла. Обычно его используют для извлечения данных для компонента (вместо этого применяйте created) и изменения DOM, зачастую ради интегрирования не-Vue библиотек.

    В методе setInterval вы используете анонимную функцию, использование ключевого слова this внутри функции будет обращаться не к vue, а к этой самой функции. Именно по этому я и переназначил конктекст

    var self = this
    


  • @Fox Спасибо за ответ! Я разобрался и вот рабочий код, который ловит логи функции и записывает в [[ParseResult]], которая уже в HTML выводится. Есть 2 кнопки Start, Pause которые запускают и останавливают функцию. Спасибо, Fox!

    $(document).ready(function() {
    
    
        var app = new Vue({
            el: '#Main',
            data() {
                return {
                   Log: [],
                   Thread: null,
                   ParseResult: "",
                   Error: ""
                   }
            },
            created() {
                let self = this
                Api.SetEventHandler(function(EventType, EventData) {
                if (EventType == "log") {
                    console.log(EventData['text'])
                    self.ParseResult = EventData["text"]
                };
    
        })
            },
            methods: {
                Parse: async function()
                {
                    ParseRun = Api.RunFunction("Parse", {})
                },
                Stop: async function() {
                    if(ParseRun)
                       ParseRun.stop()
                }
            }
        })
    

    Сейчас хочу разобраться, как мне из Log брать только значение переменной, которую я в лог передаю, без лишней информации, то есть получить: [713957403] [08:55:33] Поток №2 : 1.50 > 1.50

    Как понял в документации нет возможности такой, я могу получать только весь текст, получается только регуляркой наверно выбирать нужный мне текст или все таки можно получить только данные лога без статистики (поток, время)?



  • @Jhon said in Как в вебинтерфейсе выводить постоянно результат потока?:

    Как понял в документации нет возможности такой, я могу получать только весь текст, получается только регуляркой наверно выбирать нужный мне текст или все таки можно получить только данные лога без статистики (поток, время)?

    Вы же получаете текст лога строкой, ни кто не мешает её парсить любым удобным способом.


    На будущее, на странице интерфейса можно экспортировать и импортировать интерфейс

    526fa5dc-beaf-421f-a2a8-44d7327e224f-изображение.png

    Вот экспортированный интерфейс, в котором данные из скрипта передаются через действие "результат":
    CustomInterface.main.interface.20_08_2020_06_18.txt
    скрипт 1005.xml



  • @Fox Очень круто, я уже сам думал как результат использовать, уже продумал там скачивание, а это всего 2 строки кода! Правда вопрос - не слишком ли усложнит скрипт такая система, получение номера, скачивание, парсинга из файла?


Log in to reply