Асинхронность, 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 секунд тоже не хватает при нестабильном интернет-подключении клиента. |
Цитата:
<!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> |
С картинками так
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) // ждем, когда все загрузится } |
Спасибо большое, работает как часы. Вариант Рони тоже подходит.
Нужно постигать глубины асинхронности в JS( |
Первую задачу можно так сделать
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)); }) |
voraa, При такой реализации он немного ожидает а потом в лог мне кидает одну и ту же страницу скорее всего все 47 раз. В массив и json Тоже идет повторение одной и той же страницы информации. Как-будто бы цикл не инкрементирует.
|
Попробуй
let URL = 'здесь ссылка плюс ид страницы='+i; |
Stanislavsonder,
а если var на let поменять -- строка 11, пост #5 |
voraa,
:) |
Цитата:
Цитата:
Если нужно, могу кинуть полный код. |
Часовой пояс GMT +3, время: 20:38. |