Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 06.03.2021, 21:59
Новичок на форуме
Отправить личное сообщение для Stanislavsonder Посмотреть профиль Найти все сообщения от Stanislavsonder
 
Регистрация: 06.03.2021
Сообщений: 5

Асинхронность, Promise, Callback, onload
Добрый день! Пишу несколько решений и столкнулся в принципе с однотипной проблемой и там и там, но опишу задачи раздельно.

Задача 1. Node.js, Парсинг.
Необходимо пробежаться по некоторым URL и сохранить информацию с них в JSON файл. Все это происходит как-то так:
var request = require ('request');
var cheerio = require ('cheerio');
const fs = require('fs');

var results = new Array();
var pagesCount = 47;
for (let i = 0; i < pagesCount; i++){
	var URL = 'здесь ссылка плюс ид страницы='+i;
	request(URL, async function (error, response, html) {
	  if (!error && response.statusCode == 200) {
	    var $ = cheerio.load(html);
	    $('tr:not(.spacer)').each(function(i, element){
	     // Тут происходит много строчек кода селекторов и записи в объект data.
	      console.log(data);
	      	results.push(data);
		});
	  	}

		});
	}

// В конце мне все это нужно сохранить в JSON, То есть записать массив result

setTimeout(()=> {
	console.log('saving...');
	fs.writeFileSync("data.json", JSON.stringify(results,null,4));
},10000)



Проблема заключается в том, что 10000 (или 10 сек) это асинхронный костыль, который работает только на моей машине как надо. Если запустить это на слабом сервере - нужно будет прощупывать уже другую задержку. Как сделать так, чтобы сохранение произошло по готовности? И желательно с пояснением.
P.S. Если просто написать без timeOut, то он сохранит массив в момент начала парсинга. В итоге у меня пустой файл и запуск парсера.


Задача 2. onload для массива изображений

Есть canvas. В нем отрисовываются изображения как паттерны. Их зачастую 12 штук. Можно менять количество, не суть.
Изображения берутся с внешнего сервера и им нужно время на подзагрузку. После того как они загрузятся необходимо перерисовать canvas.

Вопрос, как проверить .onload для массива изображений, чтобы загрузились они все. Сейчас код выглядит примерно так, костыль тот же, что и раньше:

function totalUpdate() {
    setGamesForRoll();
    setTimeout(setImagesForRoll,0);
    setTimeout(drawWhell, 800);
}
function setImagesForRoll() {
    for (let i = 0; i < rollConfig.sections; i++){
    sections[i] = games[i].name;
    img[i] = new Image();
    img[i].src = games[i].imagesrc +'?rand=' + Math.random();
    img[i].width = '100px';
    img[i].height = '100px';
    }
}

Задержки в 0.8 секунд тоже не хватает при нестабильном интернет-подключении клиента.
Ответить с цитированием
  #2 (permalink)  
Старый 06.03.2021, 22:25
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Сообщение от Stanislavsonder
Задача 2. onload для массива изображений
<!DOCTYPE html>

<html>
<head>
    <title>Untitled</title>
    <meta charset="utf-8">
    <style type="text/css">
    </style>

    <script>
document.addEventListener( "DOMContentLoaded" , function() {
  "use strict"
let imgs = [
    'https://pbs.twimg.com/profile_images/717294044922187776/ojsz7uPz_400x400.jpg',
    'https://www.florissimo-shop.ru/upload/resize_cache/iblock/266/256_256_1/4100.jpeg',
    'https://cdn.shortpixel.ai/client/q_glossy,ret_img,w_256/https://iris32.ru/wp-content/uploads/s1200-256x256.jpg',
    'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRoTiQSapkMQDacdDcRC9L0OOzVYYT1HuyWTw&usqp=CAU',
    'https://ledforms.com/1906-medium_default_2x/10500120.jpg',
    'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ-KiKgpbTbFqKysnND1YAdMJ0qUSSa7bbUvA&usqp=CAU',
    'https://open3dmodel.com/wp-content/uploads/2020/03/Flowers-rose.jpg'
  ]

var ins = [];
imgs = imgs.map(src => {
  let img = new Image();
  img.src = src;
  ins.push(img);

  return new Promise(resolve => {
    img.onload = resolve
  })
})

Promise.all(imgs).then(function() {
    slider.prepend(...ins)//canvas
});
  });
    </script>
</head>

<body>
<div id="slider"></div>

</body>
</html>

Последний раз редактировалось рони, 06.03.2021 в 22:34.
Ответить с цитированием
  #3 (permalink)  
Старый 06.03.2021, 22:27
Аватар для voraa
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 2,743

С картинками так
async function totalUpdate() {
    setGamesForRoll();
    await setImagesForRoll();
    drawWhell()
}

async function setImagesForRoll() {
	let imload = []; // массив обещаний
    for (let i = 0; i < rollConfig.sections; i++){
		sections[i] = games[i].name;
		img[i] = new Image();
		img[i].src = games[i].imagesrc +'?rand=' + Math.random();
		img[i].style.width = '100px';
		img[i].style.height = '100px';
		imload.push(img[i].decode())
	}
	await Promise.all(imload)  // ждем, когда все загрузится
}
Ответить с цитированием
  #4 (permalink)  
Старый 06.03.2021, 22:45
Новичок на форуме
Отправить личное сообщение для Stanislavsonder Посмотреть профиль Найти все сообщения от Stanislavsonder
 
Регистрация: 06.03.2021
Сообщений: 5

Спасибо большое, работает как часы. Вариант Рони тоже подходит.
Нужно постигать глубины асинхронности в JS(
Ответить с цитированием
  #5 (permalink)  
Старый 06.03.2021, 22:53
Аватар для voraa
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 2,743

Первую задачу можно так сделать
var request = require ('request');
var cheerio = require ('cheerio');
const fs = require('fs');
 
var results = new Array();
var pagesCount = 47;

let prm = Promise.resolve();

for (let i = 0; i < pagesCount; i++){
    var URL = 'здесь ссылка плюс ид страницы='+i;
    prm = prm.then ( _ => new Promise (res => {
			request(URL, function (error, response, html) {
			  if (!error && response.statusCode == 200) {
					var $ = cheerio.load(html);
					$('tr:not(.spacer)').each(function(i, element){
					 // Тут происходит много строчек кода селекторов и записи в объект data.
					  console.log(data);
					  results.push(data);
					});
					res();
				}
		 
			});
		})
    )
}
 
// В конце мне все это нужно сохранить в JSON, То есть записать массив result
 
prm.then (_=> {
    console.log('saving...');
    fs.writeFileSync("data.json", JSON.stringify(results,null,4));
})
Ответить с цитированием
  #6 (permalink)  
Старый 06.03.2021, 23:17
Новичок на форуме
Отправить личное сообщение для Stanislavsonder Посмотреть профиль Найти все сообщения от Stanislavsonder
 
Регистрация: 06.03.2021
Сообщений: 5

voraa, При такой реализации он немного ожидает а потом в лог мне кидает одну и ту же страницу скорее всего все 47 раз. В массив и json Тоже идет повторение одной и той же страницы информации. Как-будто бы цикл не инкрементирует.
Ответить с цитированием
  #7 (permalink)  
Старый 06.03.2021, 23:37
Аватар для voraa
Профессор
Отправить личное сообщение для voraa Посмотреть профиль Найти все сообщения от voraa
 
Регистрация: 03.02.2020
Сообщений: 2,743

Попробуй
let URL = 'здесь ссылка плюс ид страницы='+i;
Ответить с цитированием
  #8 (permalink)  
Старый 06.03.2021, 23:39
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

Stanislavsonder,
а если var на let поменять -- строка 11, пост #5
Ответить с цитированием
  #9 (permalink)  
Старый 06.03.2021, 23:40
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,109

voraa,
Ответить с цитированием
  #10 (permalink)  
Старый 07.03.2021, 00:50
Новичок на форуме
Отправить личное сообщение для Stanislavsonder Посмотреть профиль Найти все сообщения от Stanislavsonder
 
Регистрация: 06.03.2021
Сообщений: 5

Сообщение от рони
а если var на let поменять -- строка 11, пост #5
Сообщение от voraa
let URL = 'здесь ссылка плюс ид страницы='+i;
Теперь он делает очень странные задержки по секунд 10 между итерациями, всего сделал 10 итераций и потом закончил работу, не сохранив ничего)))

Если нужно, могу кинуть полный код.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как передать два значения внутрь promise js mystica Общие вопросы Javascript 2 18.11.2018 15:25
Асинхронность callback с return и throw victornalchik Элементы интерфейса 12 25.10.2018 08:53
Как асинхронно вызвать resolve() вне Promise? Malleys Общие вопросы Javascript 8 18.12.2016 08:00
разница callback и promise A1x1On2015 Angular.js 0 13.01.2016 13:10
Работа с textarea Rompo Events/DOM/Window 14 16.12.2013 17:41