Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Асинхронность, Promise, Callback, onload (https://javascript.ru/forum/misc/82058-asinkhronnost-promise-callback-onload.html)

Stanislavsonder 06.03.2021 21:59

Асинхронность, 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 секунд тоже не хватает при нестабильном интернет-подключении клиента.

рони 06.03.2021 22:25

Цитата:

Сообщение от 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>

voraa 06.03.2021 22:27

С картинками так
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)  // ждем, когда все загрузится
}

Stanislavsonder 06.03.2021 22:45

Спасибо большое, работает как часы. Вариант Рони тоже подходит.
Нужно постигать глубины асинхронности в JS(

voraa 06.03.2021 22:53

Первую задачу можно так сделать
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));
})

Stanislavsonder 06.03.2021 23:17

voraa, При такой реализации он немного ожидает а потом в лог мне кидает одну и ту же страницу скорее всего все 47 раз. В массив и json Тоже идет повторение одной и той же страницы информации. Как-будто бы цикл не инкрементирует.

voraa 06.03.2021 23:37

Попробуй
let URL = 'здесь ссылка плюс ид страницы='+i;

рони 06.03.2021 23:39

Stanislavsonder,
а если var на let поменять -- строка 11, пост #5

рони 06.03.2021 23:40

voraa,
:)

Stanislavsonder 07.03.2021 00:50

Цитата:

Сообщение от рони
а если var на let поменять -- строка 11, пост #5

Цитата:

Сообщение от voraa
let URL = 'здесь ссылка плюс ид страницы='+i;

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

Если нужно, могу кинуть полный код.


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