Reduce period for web scraping job with puppeter node.js - node.js

I have made a job script for web scraping periodically a page and save some information in a MongoDB database. I have tried to get as much performance as i can, and for now i'm able to execute the script each 10s. However, i would like to reduce it even more, with a period between 1-10 seconds if possible. The problem is that when i reduce it, my code throws the following warning and some executions get stacked unresolved:
(node:9472) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added. Use emitter.setMaxListeners() to increase limit
Is there a way to improve the code?
const $ = require('cheerio');
const MarketModel = require('./models/marketModel');
const mongoose = require('mongoose');
const puppeteer = require('puppeteer');
var schedule = require('node-schedule');
const {
Cluster
} = require('puppeteer-cluster');
//Connection to DataBase:
mongoose.connect('mongodb://localhost:27017/Tradheo', {
useNewUrlParser: true
});
mongoose.connection.on('error', error => console.log(error));
mongoose.Promise = global.Promise;
getMarketData = async () => {
console.log("Web scraping to get market data...")
let markets = []
let marketSpain = {
country: 'Spain',
name: 'IBEX 35',
companies: []
}
let marketGermany = {
country: 'Germany',
name: 'DAX',
companies: []
}
const cluster = await Cluster.launch({
concurrency: Cluster.CONCURRENCY_PAGE,
maxConcurrency: 2,
});
await cluster.task(async ({
page,
data: url
}) => {
await page.goto({
waitUntil: 'domcontentloaded'
});
await page.setRequestInterception(true);
page.on('request', request => {
if (request.resourceType() === 'document') {
request.continue();
} else {
request.abort();
}
});
const html = await page.content();
if (url === 'https://uk.investing.com/equities/spain') {
console.log('Spain data page content loaded');
$("table[class='genTbl closedTbl crossRatesTbl elpTbl elp30'] > tbody > tr", html).each((i, elem) => {
marketSpain.companies.push({
name: $("td[class='bold left noWrap elp plusIconTd'] > a", html).eq(i).html(),
last: $("td", elem).eq(2).text(),
high: $("td", elem).eq(3).text(),
low: $("td", elem).eq(4).text(),
change: $("td", elem).eq(5).text(),
changePerCent: $("td", elem).eq(6).text(),
volume: $("td", elem).eq(7).text(),
time: $("td", elem).eq(8).text(),
purchase: false,
sale: false
});
});
markets.push(marketSpain);
} else {
console.log('Germany data page content loaded');
$("table[class='genTbl closedTbl crossRatesTbl elpTbl elp30'] > tbody > tr", html).each((i, elem) => {
marketGermany.companies.push({
name: $("td[class='bold left noWrap elp plusIconTd'] > a", html).eq(i).html(),
last: $("td", elem).eq(2).text(),
high: $("td", elem).eq(3).text(),
low: $("td", elem).eq(4).text(),
change: $("td", elem).eq(5).text(),
changePerCent: $("td", elem).eq(6).text(),
volume: $("td", elem).eq(7).text(),
time: $("td", elem).eq(8).text(),
purchase: false,
sale: false
});
});
markets.push(marketGermany);
}
if (markets.length === 2) {
MarketModel.create({
markets,
}, (err) => {
if (err) return handleError(err);
})
console.log("Done!")
}
});
cluster.queue(url1);
cluster.queue(url2);
await cluster.idle();
await cluster.close();
}
var j = schedule.scheduleJob('*/10 * 8-17 * * 1-5', function () {
const now = new Date();
//Checks that time is between 8:30 - 17:35 (schedule of the stock exchange)
if (now.getHours() >= 8 && !(now.getHours() == 8 && now.getMinutes() < 30) && now.getHours() <= 17 && !(now.getHours() == 17 && now.getMinutes() > 35)) {
getMarketData();
}
});
UPDATE: I have added some improvements like setting waitUntil property to 'domcontentloaded' and request interception to avoid waiting for images, and any kind of resources apart from html content, to be loaded. However, seems to be insufficient to achieve the goal.

Related

Adding additional spec files to an angular project, not loading/defining correctly?

Caveat: I am not the author of this project. Whoever originally wrote this is no longer with the organization and I am seemingly the most knowledgeable on this topic at this point.
I know a little about javascript and unit tests, so I successfully added one .spec.js file. I tried adding a second one for another module, reusing a lot of the spec setup, and it immediately broke.
Project resources:
Nodejs 12.16.1
jasmine-node-karma: "^1.6.1"
karma: "^6.3.12"
Contents of ./karma.conf.js:
module.exports = function(config) {
config.set({
basePath: './public',
frameworks: ['jasmine', 'jquery-3.2.1'],
files: [
"../node_modules/angular/angular.js",
"../node_modules/angular-mocks/angular-mocks.js",
"../node_modules/bootstrap/dist/js/bootstrap.js",
"../public/**/*.js",
],
exclude: [
],
preprocessors: {
},
client: {
captureConsole: true
},
browserConsoleLogOptions: {
terminal: true,
level: ""
},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['FirefoxHeadless', 'ChromeHeadlessNoSandbox', 'PhantomJS'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
},
FirefoxHeadless: {
base: 'Firefox',
flags: ['-headless'],
}
},
singleRun: false,
concurrency: Infinity
})
}
Originally I added ./public/controllers.spec.js to match the existing ./public/controllers.js. These unit tests pass and continue to do so.
Yesterday I added ./public/backups/backupcontrollers.spec.js to match ./public/backups/backupcontrollers.js.
Contents of ./public/backups/backupcontrollers.js:
/**
* Angular controller.
*/
'use strict'
const backupApp = angular.module('backup', [])
const backupTypePath = 'elasticsearch'
backupApp.controller('BackupFormController', ['$scope', '$filter', '$http', function ($scope, $filter, $http) {
console.log('Started BackupFormController')
$scope.itemInstances = []
$scope.fetchStatus = 'Ready!'
$scope.processSelection = function (item, backupType = backupTypePath) {
$scope.currentItem = item.metadata.name
$scope.getBackup(backupType)
console.log('currentItem after selecting from dropdown: ' + $scope.currentItem)
}
$scope.init = function (backupType = backupTypePath) {
$scope.refreshItemInstances(backupType)
console.log('currentItem after loading page for first time: ' + $scope.currentItem)
}
$scope.getBackup = function (backupType = backupTypePath) {
const path = `/v1/backup/${backupType}`
$scope.fetchStatus = `Fetching Backups for Item ${$scope.currentItem}...`
console.log(`Fetching backups for item from ${path}`)
$http.get('/api', { headers: { path: path, item: $scope.currentItem } })
.success(function (data, status, headers, config) {
console.log(`Got data from GET on path ${path}, HTTP status ${status}: ${JSON.stringify(data)}`)
if (typeof data === 'string' || data instanceof String) {
$scope.backups = data.split(/\r?\n/)
} else {
$scope.backups = data
}
$scope.fetchStatus = 'Ready!'
console.log('Done fetching backup list for item:' + $scope.currentItem + '!')
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
// Refresh the list of displayed Item instances
$scope.refreshItemInstances = function (backupType = backupTypePath) {
console.log('Fetching list of all items in the system ...')
$scope.fetchStatus = 'Fetching Items ... '
$http.get('/env')
.success(function (data, status, headers, config) {
console.log(data)
for (let i = 0; i < data.length; i++) {
$scope.itemInstances.push(data[i])
}
$scope.currentItem = $scope.itemInstances[0].metadata.name
console.log('Done fetching list of all items!')
console.log('currentItem after fetching list of all items: ' + $scope.currentItem)
$scope.fetchStatus = 'Ready!'
$scope.getBackup(backupType)
})
.error(function (data, status, header, config) {
console.log(data)
$scope.fetchStatus = 'Ready!'
})
}
}])
Contents of ./public/backups/backupcontrollers.spec.js:
describe('BackupFormController', function () {
let $controller, $rootScope, $httpBackend
beforeEach(module('backup'))
const mockBackupString = 'string of backup data'
const mockBackupData = {
body: mockBackupString
}
const mockItemsUnsorted = [
{
metadata: {
name: 'prod-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'dev-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
},
{
metadata: {
name: 'integ-mock-1',
spec: 'asdf',
status: 'ok'
},
notes: []
}
]
beforeEach(inject(function ($injector) {
$rootScope = $injector.get('$rootScope')
const $controller = $injector.get('$controller')
$httpBackend = $injector.get('$httpBackend')
const mockEnv = $httpBackend.when('GET', '/env')
.respond(mockItemsUnsorted)
const mockAPI = $httpBackend.when('GET', '/api')
.respond(mockBackupString)
const createController = function () {
return $controller('BackupFormController', { '$scope': $rootScope })
}
}))
describe('$scope.getBackup', function () {
beforeEach(function () {
spyOn(console, 'log')
})
it('should GET /api and set $scope.backups', function () {
controller = createController()
console.log('Dumping fetchStatus: ', $rootScope.fetchStatus)
$rootScope.init()
$httpBackend.flush()
expect($rootScope.backups).toEqual(mockBackupString)
expect(console.log).toHaveBeenCalled()
})
})
})
It seems like this new spec isn't working correctly at all; when I run npm test I see the normal successful tests from ./public/controllers.spec.js but also:
Chrome Headless 105.0.5195.125 (Mac OS 10.15.7) BackupFormController $scope.getBackup should GET /api and set $scope.backups FAILED
ReferenceError: createController is not defined
at UserContext.<anonymous> (backup/backupcontrollers.spec.js:51:7)
at <Jasmine>
This is the only output concerning ./public/backups/backupcontrollers.spec.js.
Has anybody run into this before? I found some posts regarding including angular-mocks, but as you can see in karma.conf.js, it's being included.

Firebase function will not deploy when requiring outside packages

I am having trouble deploying my web scraping function and do not know how to fix the issue.
Index.js
const functions = require("firebase-functions");
const pup = require("puppeteer");
const WebsiteData = require('./schema');
exports.scrape = functions
.runWith({ memory: '1GB' })
.pubsub.schedule('0 0 * * *')
.onRun(async (context) => {
const browser = await pup.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.setUserAgent(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'
)
var pages = [
{
name: 'aave-protocol',
fee:'0.09',
url: 'https://aave.com',
},
{
name: 'uniswap-v2',
fee:'0.30',
url: 'https://uniswap.org',
},
{
name: 'dydx',
fee:'0.00',
url: 'https://dydx.exchange',
},
{
name: 'dodo-bsc',
fee:'0.00',
url: 'https://dodoex.io',
},
{
name: 'cream-finance',
fee:'0.03',
url: 'https://cream.finance',
},
{
name: 'multiplier-finance',
fee:'0.06',
url: 'https://multiplier.finance',
}
]
var result = [];
for (var each in pages) {
await page.goto(`https://www.dapp.com/app/${pages[each].name}`, { waitUntil: 'networkidle0' })
var users = await page.evaluate(() => {
return document.querySelector('#app > div.app-container > div.root.dapp-detail > section.detail-page-outer > div > div.left-sec > div.stats-card > div.chart-section > div:nth-child(2) > div:nth-child(4) > span.value > span').innerText
})
var volume = await page.evaluate(() => {
return document.querySelector('#app > div.app-container > div.root.dapp-detail > section.detail-page-outer > div > div.left-sec > div.stats-card > div.chart-section > div:nth-child(3) > div:nth-child(4) > span.value > span:nth-child(2)').innerText
})
var obj = { "name": `${pages[each].name}`, "nDUniqueUsers": `${users}`, "nDTransactions": `${volume}`, "fee": `${pages[each].fee}`, "url": `${pages[each].url}`};
result.push(obj);
}
await browser.close();
const websiteMongo = new WebsiteData({ sites: result });
await websiteMongo.save(function(err,data){
if (err) {
console.log(err);
return null;
}
});
console.log("Done.")
return null;
});
The function is meant to use puppeteer to open up around 5 pages collect the info and upload the data to a MongoDB database. The code works perfectly in local host, but when I run firebase deploy, I get an error. Here is the error message: "Function failed on loading user code. This is likely due to a bug in the user code. Error message: Error: please examine your function logs to see the error cause: https://cloud.google.com/functions/docs/monitoring/logging#viewing_logs. Additional troubleshooting documentation can be found at https://cloud.google.com/functions/docs/troubleshooting#logging. Please visit https://cloud.google.com/functions/docs/troubleshooting for in-depth troubleshooting documentation."}"
I know that the problem consists of these two lines:
const pup = require("puppeteer");
const WebsiteData = require('./schema');
When I comment out those two lines I can deploy the function. Here is the code for schema.js:
var mongoose = require('mongoose')
mongoose.connect("URI");
var Schema = mongoose.Schema
var websiteData = new Schema({
sites: [{
name: {
type: String,
required : true,
},
nDUniqueUsers: {
type: String,
required : true,
},
nDTransactions: {
type: String,
required : true,
}, fee: {
type: String,
required : true,
}, url: {
type: String,
required : true,
}
}],
})
var WebsiteData = mongoose.model("SiteData", websiteData);
module.exports = WebsiteData
I do not know how to fix this. Any help would be greatly appreciated.
I suspect you haven't included "puppeteer" in the dependencies section of the package.json deployed alongside your function. Or possibly you've inadvertently included it in the devDependencies section instead of dependencies.
// package.json
{
// ...
"dependencies": {
"puppeteer": "^13.5.1" // be sure you have this
}
}

Return a node js response inside session.withTransaction

I am using session.withTransaction() to execute multiple updates in the mongo db. Please note that promiseArray has multiple Stock.update statements to update stock quantities.
await session.withTransaction(
async () => {
promiseResults = await Promise.all(promiseArray);
for (const result of promiseResults) {
recordCounter++;
if (result.nModified === 1) {
stockItemsNoUpdate.push(goodReturnSummary[recordCounter]);
}
}
if (stockItemsNoUpdate.length > 0) {
return res.status(200).send(response);
}
existingGoodReturnSummary = GoodReturn.build({
_id: sheetId,
goodReturnSummary,
agency,
createdBy,
});
await existingGoodReturnSummary.save({ session: session });
existingGoodReturnSummary = await GoodReturn.calculateTotalGoodReturnAmount(
existingGoodReturnSummary,
session
);
},
{
readPreference: 'primary',
readConcern: { level: 'local' },
writeConcern: { w: 'majority' },
}
);
If stockItemsNoUpdate.length > 0 I need to abort this transaction and send the response. done by below code segment.
if (stockItemsNoUpdate.length > 0) {
return res.status(200).send(response);
}
But I cannot do this because of the below error
Any idea on how to resolve this ??
Cheers
See Nodejs mongodb's Transaction API `withTransaction` always return null and https://jira.mongodb.org/browse/NODE-2014.
https://jira.mongodb.org/browse/NODE-2014?focusedCommentId=2420255&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-2420255 provides a workaround.

How to generate tables rows dynamically in Nodejs using ESCPOS API module

A few days ago I was struggling to get to print receipts using ESCPOS Java API but failed since I couldn't find a simple enough USB API to allow the program to print to my thermal printer using a USB interface. I later decided to implement this in Node and ESCPOS module.
I am connecting this application to MySQL database to be able to print receipts from recorded transactions. I am using tables to create a list of products and their respective prices but only by hard coding. My problem now is how to create these tables dynamically. Depending on which products were involved in the transaction, I want the script to query and print only those.
Here is receipt code!
const db = require('./database.js');
const escpos = require('escpos');
const uniqueRandom = require('unique-random');
const random = uniqueRandom(1000, 9999);
const device = new escpos.USB();
const options = { encoding: "GB18030" }
exports.printGeneralReceipt = function(status){
db.getTransactionDetails(function(res){
data = res;
});
const printer = new escpos.Printer(device, options);
console.log("Printer found!");
device.open(function(){
console.log("Receipt generating...");
printer
.font('b')
.align('ct')
.style('bu')
.size(1, 1)
.encode('utf8')
.text('\n*****START OF LEGAL RECEIPT*****'+
'\n\nCOMPUTICKET MALAWI\n'+
'SHOP 31A, GAME COMPLEX\n'+
'LILONGWE MALL\n\nwww.computicket.mw\n+265 (0) 99 974 7576\n')
.table(["BUYER NAME :", "CLIFFORD MWALE", ""])
.table(["RECEIPT # :", random(), ""])
.table(["DATE: ", "12/AUG/2019", ""])
.text("----------ITEM LIST----------\n")
// ITEM LIST STARTS HERE
.table(["MILK","$2"])
.table(["PEANUT BUTTER", "$6"])
// ITEM LIST ENDS HERE
.text("--------------------------------")
.table(["TOTAL PRICE", "$8.00", ""])
.text("Operator: Jon Doe\n-------------------------------\n")
.barcode('123456789012')
.text("\n\nTHANK YOU\n\n*****END OF LEGAL RECEIPT*****")
.beep(1,100)
.cut().close();
console.log("Receipt printed!");
});
}
And here is the function pulling the transaction details from the Database. I'll spare you the overhead of creating a connection.
exports.getTransactionDetails = function(trans_id){
var res = "";
conn.query("SELECT * FROM transactions JOIN products_in_transaction WHERE transactions.trans_id = products_in_transaction.trans_id "+
" transactions.trans_id = '"+trans_id+"'",
function (error, results, fields) {
for(var i = 0; i < results.length; i++){
// SOME OPERATION HERE
}
});
}
I will post some code I played with, and it worked;you need to install html-to-text
const escpos = require('escpos');
// Select the adapter based on your printer type
const device = new escpos.USB();
const printer = new escpos.Printer(device);
const cartItems = [
{category: 'test', price: 80, quantityToSell: 2, title: 'Hosting'},
{category: 'test1', price: 820, quantityToSell: 63, title: 'Mouse'},
{category: 'test00', price: 60, quantityToSell: 20, title: 'Sale'},
{category: 'dvhfgnfgjfjg', price: 20, quantityToSell: 8, title: 'Keyboards'},
{category: 'dvhfgnfgjfjg', price: 10, quantityToSell: 4, title: 'Keyss'},
{category: 'dvhfgnfgjfjg', price: 70, quantityToSell: 1, title: 'Test'},
{category: 'dvhfgnfgjfjg', price: 500, quantityToSell: 12, title: 'Whale oil'},
{category: 'dvhfgnfgjfjg', price: 560, quantityToSell: 22, title: 'Papers'},
]
// get total per line items
const totalPerItemList = (item) => {
let totalPerItem = 0
totalPerItem = item.quantityToSell * item.price
return totalPerItem
}
// get the total price
let total = 0;
for (let cartItem of cartItems) {
var unitSum = cartItem.quantityToSell * cartItem.price
total += unitSum
}
// Create our html template, could be an html file on it's own
const TestTable = `
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Testing Title for table</title>
</head>
<body>
<div class="invoice-box">
<table class="receipt-table" cellpadding="0" cellspacing="0" border="0">
<thead>
<tr class="heading">
<th>Item</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
${cartItems.map(item =>
`
<tr>
<td>${item.title}</td>
<td>${item.quantityToSell}</td>
<td>${item.price}</td>
<td>${totalPerItemList(item)}</td>
</tr>
`
)}
</tbody>
<tfoot>
<tr>
<td>
TOTAL:${total}
</td>
</tr>
</tfoot>
</table>
</div>
</body>
</html>
`
const htmlToText = require('html-to-text');
const text = htmlToText.fromString(TestTable, {
wordwrap: false,
tables: ['.receipt-box', '.receipt-table']
});
device.open(function(err){
printer
.font('a')
.align('ct')
.style('bu')
.size(1, 1)
.text('Printing Tables Dynamically with epos')
.text('||||||||||||||||||||||||||')
.text(text)
.text('||||||||||||||||||||||||')
.text('========================')
.cut()
.close()
});
the fastest way to do this ive found is to do what ive done in my own project as in
'use strict'
import { app, protocol, BrowserWindow,ipcMain } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
const escpos = require('escpos');
escpos.USB = require('escpos-usb');
const isDevelopment = process.env.NODE_ENV !== 'production'
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
{ scheme: 'app', privileges: { secure: true, standard: true } }
])
async function createWindow() {
// Create the browser window.
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
}
})
win.menuBarVisible = false;
if (process.env.WEBPACK_DEV_SERVER_URL) {
// Load the url of the dev server if in development mode
await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// Load the index.html when not in development
win.loadURL('app://./index.html')
}
}
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
try {
await installExtension(VUEJS_DEVTOOLS)
} catch (e) {
console.error('Vue Devtools failed to install:', e.toString())
}
}
createWindow()
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', (data) => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
function print(load){
var _message = '';
device.open(function(){
_message = 'done'
printer
.font('a')
.align('ct')
.style('bu')
.size(0.05, 0.05)
.text('Road House Magodo')
.text('Magodo Shopping Arcade Ayodele \r\n Fanoki Magodo Phase I')
.table(['item','qty','total'])
load.load.forEach((element)=>{
return printer.table(element)
})
printer.text(`Total: ${load.total}`)
if(load.change!='card'){
printer.text(`Change: ${load.change}`)
}else{
printer.text('Method: Card')
}
printer.newLine()
printer.newLine()
printer.cut()
printer
.font('a')
.align('ct')
.style('bu')
.size(0.05, 0.05)
.text('Road House Magodo')
.text('Magodo Shopping Arcade Ayodele \r\n Fanoki Magodo Phase I')
.table(['item','qty','total'])
load.load.forEach((element)=>{
return printer.table(element)
})
printer.text(`Total: ${load.total}`)
if(load.change!='card'){
printer.text(`Change: ${load.change}`)
}else{
printer.text('Method: Card')
}
printer.newLine()
printer.newLine()
printer.cut()
printer
.font('a')
.align('ct')
.style('bu')
.size(0.05, 0.05)
.text('Road House Magodo')
.text('Magodo Shopping Arcade Ayodele \r\n Fanoki Magodo Phase I')
.table(['item','qty','total'])
load.load.forEach((element)=>{
return printer.table(element)
})
printer.text(`Total: ${load.total}`)
if(load.change!='card'){
printer.text(`Change: ${load.change}`)
}else{
printer.text('Method: Card')
}
printer.newLine()
printer.cut()
printer.close()
},error=>{
if(error){
console.log(error)
_message = error+'error'
return
}
})
return _message
}
const device = new escpos.USB();
const printer = new escpos.Printer(device);
ipcMain.on('print', (_,load) => {
let _fish =()=>{
return print(JSON.parse(load))
}
_.reply(_fish());
})
basically passing your array or object and looping through it.

Dynamic props in vnode doesn't work, in elementui

I want to use a dynamic prop in vnode, but it doesn't work
const h = this.$createElement;
this.$notify({
message: h('el-progress', {
props: {
percentage: this.percentage,
},
}),
duration: 0,
customClass: 'download-progress-container',
});
setInterval(() => {
this.percentage += 1;
}, 1000);
I expect the progress bar 's percentage changed as the parent's prop, but it doesn't

Resources