Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Перебор эл. массива с целью присвоения значения переменной. (https://javascript.ru/forum/events/83058-perebor-ehl-massiva-s-celyu-prisvoeniya-znacheniya-peremennojj.html)

uzlprog 04.09.2021 12:23

Перебор эл. массива с целью присвоения значения переменной.
 
Всем доброго дня! Задача такая: есть массив данных arr, мне нужно стряпать функцию, которая бесконечно (по кругу) перебирает значения каждого элемента массива через определенное время (1 сек) и присваивает это значение переменной a. При обращении она должна возвращать текущее значение переменной а.

Я новичок в JS, пробовал по разному, но не получается... Посоветовали сделать так:

let a;
function f(i = 0) {
  if (i == arr.length) i = 0;
  a = arr[i++];
  //console.log(a);
  setTimeout(() => {
    f(i);
  }, 1000);
}


Мне нужно вместо //console.log(a); вернуть текущее значение а. Я по разному переписывал этот код, но ничего не получается. Я не пойму в чем дело? Куда нужно вставить return(a)? Или при такой конструкции не получится вернуть текущее значение?

Aetae 04.09.2021 12:52

"...при обращении к переменной" наверное у тебя в задаче было.
И у тебя уже всё работает. Запустил функцию - она в фоне работает, в любой момент можешь в консоли написать console.log(a) и увидеть текущую a. Куда ты хочешь что return - непонятно.

В общем что-то ты не так понял в задании, и сам небось не понимаешь конечного результата.

рони 04.09.2021 19:13

:) :write:
<script>
function fun(arr) {
    let time = performance.now();
    Object.defineProperty(window, "a", {
        get: function() {
            let i = Math.trunc((performance.now() - time)/1000) % arr.length;
            return arr[i]
        }
    });
    return window.a
}
fun([1, 2, 3, 4, 5]);
window.setInterval(_ => document.body.append(`${a} `) , 1001)
</script>

uzlprog 06.09.2021 08:15

Цитата:

В общем что-то ты не так понял в задании, и сам небось не понимаешь конечного результата.
Задание тут не причем, мне нужен практический результат. В функции основного скрипта (вызывается по действию пользователя) необходимо использовать переменную a значение которой выбирается из массива (100 элементов) перебор которых происходит циклически независимо в фоне. Перебор в фоне работает, а вот при использовании a у меня выдает unindeficated


var a;
function f(i = 0) {
  if (i == arr.length) i = 0;
  a = arr[i++];
  setTimeout(() => {
    f(i);
  }, 1000);
}

function N1() {
var b;
b = a + 12;
return(b);
}

uzlprog 06.09.2021 08:18

рони, спасибо, но я пытаюсь понять почему не работает вышеописанный пример.

uzlprog 06.09.2021 08:30

Все разобрался, я обернул код в функцию, но ее не вызываю, соответственно a у меня вообще не генерится))

uzlprog 06.09.2021 08:51

Все равно столкнулся с проблемой. Код генерирует a один раз, то есть переменная у меня почему-то не меняется, если я например забью ее значением массив:

var a;
function f(i = 0) {
  if (i == arr.length) i = 0;
  a = arr[i++];
  setTimeout(() => {
    f(i);
  }, 1000);
}

function N1() {
let c = 0;
let arr2 = [];
let N = 100;
for (var k = 1; k <= N; k++) {
   arr2.push(a);
   document.write('Item: ' + arr2[c++] + ' of ' + arr2.length + '<br/>');
}
}


У меня выдает список, в котором все 100 элементов равны одному и тому же значению переменной a.

Соответственно, как я понимаю, чтобы динамически обращаться к первоначальному коду, нужно его обернуть в функцию,

function N0() {
var a;
function f(i = 0) {
  if (i == arr.length) i = 0;
  a = arr[i++];
  setTimeout(() => {
    f(i);
  }, 1000);
}
return(a);
}

function N1() {
let c = 0;
let arr2 = [];
let N = 100;
let b;
for (var k = 1; k <= N; k++) {
   b =  N0();
   arr2.push(a);
   document.write('Item: ' + arr2[c++] + ' of ' + arr2.length + '<br/>');
}
}


Вообще не робит(((...

voraa 06.09.2021 09:35

Трудно понять чего вы хотите.
Что бы функция f начала выполняться, ее надо вызвать. Где вызов?

Цикл for (var k = 1; k <= N; k++) быстренько пробежится и закончится. Он не будет ждать пока будут срабатывать все вызовы timout.

Изучайте возможности асинхронного программирования в javascipt.
Promise, async/await.

uzlprog 06.09.2021 10:41

Формализую задачу: необходимо создать массив, и заполнить его динамическим значением переменной a, которая с периодом в 1 сек. принимает значения элементов первоначального массива.

uzlprog 06.09.2021 10:46

var a;
async function f(i = 0) {
  if (i == arr.length) i = 0;
  a = arr[i++];
  setTimeout(() => {
    f(i);
  }, 1000);
}
f();
function N1() {
let c = 0;
let arr2 = [];
let N = 100;
let b;
for (var k = 1; k <= N; k++) {
   arr2.push(a);
   document.write('Item: ' + arr2[c++] + ' of ' + arr2.length + '<br/>');
}
}


Что не правильно?!

uzlprog 06.09.2021 10:49

Цитата:

Цикл for (var k = 1; k <= N; k++) быстренько пробежится и закончится. Он не будет ждать пока будут срабатывать все вызовы timout.
А как задать циклу for задержку?

voraa 06.09.2021 11:14

Цитата:

Сообщение от uzlprog
А как задать циклу for задержку?

Какую?

const arr0 = [0,1,2,3,4]; // Исходный массив
let a; // Будет каждую сек циклически получать значение следующего элемента
function f(arr, i = 0) {
  i %= arr.length;
  a = arr[i];
  setTimeout(() => {() => f(arr, i+1), 1000);
}

f(arr0);


Запустили цикл с таймерами. Сначала а=0, через секунду а=1, потом а=2 и т.д.
Дальше чего вы хотите?
В какой момент времени вы хотите получить другой массив и чем его заполнять?

Только учтите, что в javascript работающий код никто не может прервать. Пока он не завершится (например какой нибудь цикл) никакое другое событие обрабатываться не будет. Даже функция заданная в таймере.
setTimeout - это не выполни функцию через заданное время (как неправильно пишут во многих учебниках). Это поставь функцию в очередь на выполнение через заданное время. А выполняться она будет, когда дойдет очередь. Если какая то задача в очереди (даже та сама, которая вызвала setTimeout будет работать слишком долго, то функция, заданная в setTimeout будет ждать.

Alexandroppolus 06.09.2021 12:07

Цитата:

Сообщение от uzlprog
Задача такая: есть массив данных arr, мне нужно стряпать функцию, которая бесконечно (по кругу) перебирает значения каждого элемента массива через определенное время (1 сек) и присваивает это значение переменной a. При обращении она должна возвращать текущее значение переменной а.

function createFunc(arr, interval) {
    let i = 0;
    setInterval(() => { i = (i + 1) % arr.length; }, interval);
    return () => arr[i];
}


const func = createFunc([11, 22, 33, 44], 1000);

...

// будет возвращать тот элемент массива, который сейчас выбран. 
// выбор меняется раз в секунду по кругу
alert(func());


как вариант, можно добавить в функцию останавливатель и запускатель таймера, но кажется это сейчас без надобности.
так же - запускать таймер при первом вызове функции, а не при создании. Это надо?

uzlprog 07.09.2021 07:29

Цитата:

Запустили цикл с таймерами. Сначала а=0, через секунду а=1, потом а=2 и т.д.
Дальше чего вы хотите?
В какой момент времени вы хотите получить другой массив и чем его заполнять?
Через каждую секунду значение переменной а меняется - это понятно, так и должно быть.

Первый вариант:

Мне нужно получать значение переменной через некоторое время t. Допустим через 9 сек. То есть какое значение будет принимать a каждые 9 сек. (при условии что а меняет свое значение каждую секунду). Заранее это время t не определено. То есть время через которое мне нужно снимать значение переменной а каждый раз разное. Вот значениями, которое а принимает через заданное на один сеанс запуска скрипта время t мне и нужно заполнять массив.

Второй вариант:

Пользователь кликает по кнопке и текущее значение а добавляется в массив. Но второй вариант не обязателен.

Aetae 07.09.2021 08:43

uzlprog, второй вариант прост:
<input type="button" id="button" value="add a"/>
<div>Выходной массив: <span  id="out">[]</span></div>
<script>
var a;
var arr = [1, 2, 3, 4, 5];
var outArr = [];
function f(i = 0) {
  if (i == arr.length) i = 0;
  a = arr[i++];
  setTimeout(() => {
    f(i);
  }, 1000);
}
f();

function add() {
  outArr.push(a);
  out.innerHTML = JSON.stringify(outArr);
}

button.onclick = add;
</script>


Первый вариант не будет иметь никакой точности. Потому что время срабатывания таймеров не может быть точным. Ты думаешь что при интервале в 1 секунду обновления а, если спрашивать каждую 9ую секунду получишь 9ое значение а? А вот и нет. Там может быть 8ое или 10ое, а может и 35ое, если ты вкладками щёлкал или запускал что-то с нагрузкой процессора.
Таймер не гарантируют точное время, при установке таймера в N он сработает после N. Когда после - зависит от окружения.

<input type="button" id="button" value="stop"/>
<div>Выходной массив: <span  id="out">[]</span></div>
<script>
var a;
var arr = [1, 2, 3, 4, 5];
var outArr = [];
function f(i = 0) {
  if (i == arr.length) i = 0;
  a = arr[i++];
  setTimeout(() => {
    f(i);
  }, 1000);
}
f();

function add() {
  outArr.push(a);
  out.innerHTML = JSON.stringify(outArr);
}

function fill(t = 9) {
  add();
  fill.timerId = setTimeout(() => {
    fill(t);
  }, t * 1000);
}
fill();

button.onclick = () => clearTimeout(fill.timerId);
</script>

uzlprog 07.09.2021 10:58

Aetae, спасибо. С пользовательским вводом я разобрался, а вот первый вариант... Ваш код почему-то у меня выдает:
Выходной массив: [1]


И все...

uzlprog 07.09.2021 10:59

Цитата:

Первый вариант не будет иметь никакой точности. Потому что время срабатывания таймеров не может быть точным. Ты думаешь что при интервале в 1 секунду обновления а, если спрашивать каждую 9ую секунду получишь 9ое значение а? А вот и нет. Там может быть 8ое или 10ое, а может и 35ое, если ты вкладками щёлкал или запускал что-то с нагрузкой процессора.
Таймер не гарантируют точное время, при установке таймера в N он сработает после N. Когда после - зависит от окружения.
Этот момент я не учел. Но теперь уже просто интересна реализация.

Aetae 07.09.2021 13:32

Цитата:

Сообщение от uzlprog (Сообщение 540062)
Aetae, спасибо. С пользовательским вводом я разобрался, а вот первый вариант... Ваш код почему-то у меня выдает:
Выходной массив: [1]


И все...

Подожди 9+ секунд.)


Часовой пояс GMT +3, время: 06:00.