When entering a screen, 5 promises are loaded automatically, I use a promise.all, the problem is that they are executed randomly, within each function I use a push where I put the information.
The problem is that I have to change the push for a splice because the promise.all is loaded randomly and with the push I can't know which place to assign to each information of each "function". Here is my code:
At the beginning it loads the promises
ngOnInit(): void {
Promise.all([this.getData1(), this.getData2()]).then(values => {
console.log(values)
this.processing = true;
}).catch(reason => {
console.log('error get data',reason)
});
}
I only put 2 as an example but in the other functions it is the same
public getData1() {
return new Promise((resolve, reject) => {
this.createService.getServiceData1().subscribe(
(response: any) => {
let customFieldOption: CustomFieldOption = new CustomFieldOption();
this.opcionServicio = response;
this.opcionesServicio.push(this.opcionServicio);
this.servicio.push(this.opcionesServicio[0].ticket_field.title)
customFieldOption.id = this.opcionServicio.ticket_field.id;
customFieldOption.name = this.opcionServicio.ticket_field.title;
this.customFieldOptions.push(customFieldOption);
resolve(true);
},
(error) => {
console.log(error);
reject(true);
}
);
});
}
public getData2() {
return new Promise((resolve, reject) => {
this.createService.getServiceData2().subscribe(
(response: any) => {
let customFieldOption: CustomFieldOption = new CustomFieldOption();
this.opcionServicio = response;
this.opcionesServicio.push(this.opcionServicio);
this.servicio.push(this.opcionesServicio[0].ticket_field.title)
customFieldOption.id = this.opcionServicio.ticket_field.id;
customFieldOption.name = this.opcionServicio.ticket_field.title;
this.customFieldOptions.push(customFieldOption);
resolve(true);
},
(error) => {
console.log(error);
reject(true);
}
);
});
}
You can use an array with indexes instead of push or an object with static keys.
Example 1:
You can put data1 to this.opcionesServicio[0] and data2 to this.opcionesServicio[1]. Then you know that they can be always accessed by the same index.
opcionesServicio = [];
public getData1(dataIndex = 0) {
return new Promise((resolve, reject) => {
this.createService.getServiceData1().subscribe((response: any) => {
this.opcionesServicio[dataIndex] = respoosne;
});
});
}
public getData2(dataIndex = 1) {
return new Promise((resolve, reject) => {
this.createService.getServiceData2().subscribe((response: any) => {
this.opcionesServicio[dataIndex] = respoosne;
});
});
}
// Access
const data1 = this.opcionesServicio[0];
const data2 = this.opcionesServicio[1];
Example 2:
You can store the data in an object instead.
data1 goes to this.opcionesServicio['data1'] and data2 to this.opcionesServicio['data2']. Then you can access them by the data1, data2 keys.
opcionesServicio = {};
public getData1(dataName = 'data1') {
return new Promise((resolve, reject) => {
this.createService.getServiceData1().subscribe((response: any) => {
this.opcionesServicio[dataName] = respoosne;
});
});
}
public getData2(dataName = 'data2') {
return new Promise((resolve, reject) => {
this.createService.getServiceData2().subscribe((response: any) => {
this.opcionesServicio[dataName] = respoosne;
});
});
}
const data1 = this.opcionesServicio['data1'];
const data2 = this.opcionesServicio['data2'];
Related
Hello I am stuck with indexedDB. When I try to store an array of links, it fails with no errors or exceptions.
I have two code examples. This one works fine:
export const IndexedDB = {
initDB(): Promise<string> {
return new Promise((resolve, reject) => {
const open = indexedDB.open("MyDB", 1);
open.onupgradeneeded = function () {
open.result.createObjectStore("store", { keyPath: "id" });
resolve("Database initialized successfully...");
};
open.onerror = function (err) {
reject(err);
};
open.onsuccess = function () {
resolve("Database initialized successfully...");
};
});
},
getAll(): Promise<Values> {
return new Promise((resolve, reject) => {
const open = indexedDB.open("MyDB", 1);
open.onerror = function (err) {
reject(err);
};
open.onsuccess = function () {
const tx = open.result.transaction("store", "readonly");
const store = tx.objectStore("store");
const getFromStore = store.getAll();
getFromStore.onerror = function (err) {
reject(err);
};
getFromStore.onsuccess = function () {
resolve(getFromStore.result);
};
};
});
},
putMany(values: Values): Promise<void> {
return new Promise((resolve, reject) => {
const open = indexedDB.open("MyDB", 1);
open.onerror = function (err) {
reject(err);
};
open.onsuccess = function () {
values.forEach((value: Value) => {
const tx = open.result.transaction("store", "readwrite");
const store = tx.objectStore("store");
const putInStore = store.put(value);
putInStore.onerror = function (err) {
reject(err);
};
});
resolve();
};
});
},
};
App.tsx:
export const saveValues = (values: Values): Promise<void> => {
IndexedDB.putMany(values);
};
export const App: React.FunctionComponent = () => {
const valuesForTest: Values = [
{
id: Math.random(),
text: "Hello world!"
},
{
id: Math.random(),
text: "Hello world!"
},
{
id: Math.random(),
text: "Hello world!"
}
];
useEffect(() => {
saveValuesToDB(valuesForTest);
}, []);
return (
<SomeComponent/>
);
};
And this one always fails. No errors or exceptions at all. The data just isn't saved.
The main difference is just data types. The first example uses the "Values" type, and the second uses the "Links" type.
export const IndexedDB = {
initDB(): Promise<string> {
return new Promise((resolve, reject) => {
const open = indexedDB.open("MyDB", 1);
open.onupgradeneeded = function () {
open.result.createObjectStore("store", { keyPath: "href" });
resolve("Database initialized successfully...");
};
open.onerror = function (err) {
reject(err);
};
open.onsuccess = function () {
resolve("Database initialized successfully...");
};
});
},
getAll(): Promise<Links> {
return new Promise((resolve, reject) => {
const open = indexedDB.open("MyDB", 1);
open.onerror = function (err) {
reject(err);
};
open.onsuccess = function () {
const tx = open.result.transaction("store", "readonly");
const store = tx.objectStore("store");
const getFromStore = store.getAll();
getFromStore.onerror = function (err) {
reject(err);
};
getFromStore.onsuccess = function () {
resolve(getFromStore.result);
};
};
});
},
putMany(values: Links): Promise<void> {
return new Promise((resolve, reject) => {
const open = indexedDB.open("MyDB", 1);
open.onerror = function (err) {
reject(err);
};
open.onsuccess = function () {
values.forEach((value: Link) => {
const tx = open.result.transaction("store", "readwrite");
const store = tx.objectStore("store");
const putInStore = store.put(value);
putInStore.onerror = function (err) {
reject(err);
};
});
resolve();
};
});
},
};
App.tsx:
export const saveValues = (values: Links): Promise<void> => {
IndexedDB.putMany(values);
};
export const App: React.FunctionComponent = () => {
const valuesForTest: Links = [
{
href: "https://somelink1.com/",
name: "Link"
},
{
href: "https://somelink2.com/",
name: "Link"
},
{
href: "https://somelink3.com/",
name: "Link"
},
];
useEffect(() => {
saveValuesToDB(valuesForTest);
}, []);
return (
<SomeComponent/>
);
};
Can you help me?
If you created the database with the first code snippets, your "store" object store will be using id as keyPath. If you want to change this to href as in your second snippet, delete the database first (in the browser devtools), then run your second snippet.
Kindly note that if you want to make schema changes to an existing database (without deleting it), you will have to pass a higher version number to indexedDB.open to trigger your onupgradeneeded callback: indexedDB.open("MyDB", 2);. If the database exists with the same version, that callback will (obviously) not be executed because it doesn't need upgrading.
Also note that if you want to use both your code snippets to store different things (values and links), use separate object stores for them: createObjectStore("values", { keyPath: "id" }) and createObjectStore("links", { keyPath: "href" })
Last but not least, for easier IndexedDB usage I can really recommend to use AceBase (fullblown realtime database) or Dexie (simple IndexedDB wrapper) instead. Those are easy to use and handle all IndexedDB plumbing!
EDIT: In your putMany method I also see you call resolve in the open.onsuccess callback, instead of waiting until all of your put operations have succeeded. That's why you don't get an error, reject will be called after resolve so that does nothing.
I'm always getting response as 0 for this count but is 1 when I query DB straight. What am I missing here?
const getItemsCount = (db, applicationId, typeId) => new Promise((resolve, reject) => {
const existsStatement = `SELECT COUNT(ITEMIDENTIFIER) AS ITCOUNT
FROM LISTITEMS
WHERE WORKLISTREFERENCEIDENTIFIER = '${applicationId}'
AND TYPEID = '${typeId}'`;
db.executeQuery(existsStatement)
.then((result) => {
resolve(parseInt(result[0].ITCOUNT, 10));
})
.catch((error) => {
reject(error);
});
});
populate(applicationId, data) {
const ITM = this;
ITM.populatePromise = new Promise(async (resolve, reject) => {
if (!data || !data.typeId) {
reject(new Error('Body parameters missing'));
}
await queries.getWorklistItemsCount(ITM.db, applicationId, data.typeId).then((result)=>{
resolve(result)
})
})
}
I am trying to export the value with instrument variable. however data is returning as [object Promise] than object. How can I assign module variable with the final result rather than the promise object.
var instruments = {
data: async () => {
return new Promise((resolve, reject) => {
/// Respond after retrieving the data
resolve({result : "...." }
);
}
}
var symbols = async () => {
const res = await instruments.data();
return res;
}
module.exports.instrument = symbols().then((data) => {
console.log('data');
return data;
}).catch((e) => {
console.log('error');
return {}
});
It looks like you want a singleton cache. Here is a basic implementation
cache.js
let data = {}
module.exports = {
getData: () => {
return data
},
setData: newData => {
data = newData
return
},
}
No need for async here. I would separate this code with the code that retrieves data.
fetchData.js
const cache = require('./cache')
const fetchData = () => {} // fetch data code here
fetchData().then(data => {
cache.setData(data)
})
try this
var instruments = {
data: () => {
return new Promise((resolve, reject) => {
/// Respond after retrieving the data
resolve({result : "...." });
}
}
var symbols = async () => {
const res = await instruments.data();
return res;
}
module.exports.instrument = symbols;
then import instrument method to call and then call
const instrument = require("./filepath");
instrument().then((data) => {
console.log('data');
}).catch((e) => {
console.log(e);
});
If your async function instruments.data() called, it'll await return Promise.
just append await at return for your expected result.
var instruments = {
data: async () => {
return await new Promise((resolve, reject) => {
// Respond after retrieving the data
resolve({result : "...." });
}
}
or remove async. it's same as above.
var instruments = {
data: () => {
return new Promise((resolve, reject) => {
// Respond after retrieving the data
resolve({result : "...." });
}
}
I have this nested loop of promises and at then end a for loop that pushes items in the files array.
public async content() {
let files = [];
return new Promise(async (resolve, reject) => {
await this.axios.get(this.currentRequest).then(async biosample => {
await this.axios.get(this.currentRequest + biosample.data.item).then(async datasets => {
for (let i = 0; i < datasets.data.Items.length; i++) {
await this.axios.get(this.currentRequest + datasets.data.Items[i].Id).then(response => {
files.push(response.data.Item);
}).catch(reason => {
reject(reason)
});
}
})
}).catch(function (error) {
reject(new Error(error.response))
});
resolve(files)
})
}
The calls are made correctly, because if I use Promise.all([promises here]), then it works. But I'm trying to learn to chain promises properly.
When I'm debugging with webstorm datasets seems to be defined and have the necessary properties.
Schematically you code must like this
content() {
return Promise.resolve()
.then(_ => this.axios.get(this.currentRequest)
.then(biosample => this.axios.get(this.currentRequest + biosample.data.item))
.then(datasets => Promise.all(datasets.data.Items.map(item => this.axios.get(this.currentRequest + item.Id))))
}
You're not using the potential of await. Your code can be as simple at this:
public async content() {
let files = [];
return new Promise(async (resolve, reject) => {
try {
let biosample = await this.axios.get(this.currentRequest)
let datasets = await this.axios.get(this.currentRequest + biosample.data.item)
for (let i = 0; i < datasets.data.Items.length; i++) {
let response = await this.axios.get(this.currentRequest + datasets.data.Items[i].Id)
files.push(response.data.Item);
}
resolve(files)
} catch(error) {
reject(new Error(error.response || error))
};
})
}
I have a class that loads indexedDB. Before methods in the class can access it, I need to have indexedDB loaded beforehand. Currently I'm using an init() method prior to any other method that does not have this.db initialized.
I'm looking for a cleaner way to implement what I have, which definitely isn't DRY. Essentially every method is currently implemented with the same code pattern below.
Problem points are:
The requirement of another method init() in order to properly
handle the intialization of indexedDB.
The if (!this.db) { segment that ends up repeating itself later.
export default class Persist {
constructor(storage) {
if (storage) {
this.storage = storage;
}
else {
throw new Error('A storage object must be passed to new Persist()');
}
}
// needed to ensure that indexedDB is initialized before other methods can access it.
init () {
// initialize indexedDB:
const DBOpenRequest = this.storage.open('db', 1);
DBOpenRequest.onupgradeneeded = () => {
const db = DBOpenRequest.result;
db.createObjectStore('db', { keyPath: 'id', autoIncrement: true });
};
return new Promise((resolve, reject) => {
DBOpenRequest.onerror = event => {
reject(event);
};
DBOpenRequest.onsuccess = event => {
console.log(`IndexedDB successfully opened: ${event.target.result}`);
resolve(event.result);
this.db = DBOpenRequest.result;
};
});
}
toStorage(session) {
if (!this.db) {
return this.init().then(() => {
const db = this.db;
const tx = db.transaction('db', 'readwrite');
const store = tx.objectStore('db');
const putData = store.put(session.toJS());
return new Promise((resolve, reject) => {
putData.onsuccess = () => {
resolve(putData.result);
};
putData.onerror = () => {
reject(putData.error);
};
});
});
}
// basically a repeat of above
const db = this.db;
const tx = db.transaction('db', 'readwrite');
const store = tx.objectStore('db');
const putData = store.put(session.toJS());
return new Promise((resolve, reject) => {
putData.onsuccess = () => {
resolve(putData.result);
};
putData.onerror = () => {
reject(putData.error);
};
});
}
indexedDB provides asynchronous functions. indexedDB.open is an asynchronous function. It looks like you are trying to work with indexedDB in a non-asynchronous manner. Instead of storing the IDBDatabase variable as a property of the instance of your class, just return it as the resolve value and manage it external to the class.
function connect(name, version) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(name, version);
request.onupgradeneeded = myUpgradeHandlerFunction;
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
request.onblocked = () => { console.log('blocked'); };
});
}
function doStuffWithConn(conn, value) {
return new Promise((resolve, reject) => {
const tx = conn.transaction(...);
const store = tx.objectStore(...);
const request = store.put(value);
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
async function putValue(value) {
let conn;
try {
conn = await connect(...);
await doStuffWithConn(conn, value);
} catch(exception) {
console.error(exception);
} finally {
if(conn)
conn.close();
}
}