问题
I am making an app for Android in Cordova, with Typescript, and I bundle with Webpack. I don't understand very well how to do asynchronous tasks in Javascript. I saw several tutorials on callbacks and promises, but it's still very confused for me and I don't manage to adapt it to my code. I don't know if my problem comes from my code itself, or from Typescript/Cordova/Webpack.
I created a function getAllSMS
that return a big object, and takes some time to execute. I know the function works because if I try to print the allSMS
variable in the inspector's console, it's empty at first and then filled in like 1 second. (I think that behavior of the inspector is quite strange, but it really does that).
I saw I can do asynchronous tasks with promises, but I have some problems to understand how it works. I have seen several tutorials but I still don't understand how to apply it to my code.
Thanks
[EDIT] : Here's my getAllSMS function converted to a promise :
public getAllSMS() {
return new Promise(//return a promise
(resolve,reject)=>{
if (SMS) {
SMS.listSMS(this.filters, function (data) {
resolve(data);//added this, resolve promise
}, function (err) {
console.log('error list sms: ' + err);
reject(err);//added this reject promise
});
}else{
resolve([]);//added this, resolving to empty array?
}
}
).then(
data=>{
let contacts = {};
for (let key in data) {
if ((data[key].address).length > 7 && (data[key].address).match("[0-9]+")) {
let date = SMSManager.convertUnixDate(data[key].date); // on converti le format de date de listSMS
if (contacts.hasOwnProperty(data[key].address)) {
Object.defineProperty(contacts[data[key].address], data[key]._id, {
value: {
"body": data[key].body,
"date": date
}
});
} else {
let myid = String(data[key]._id);
Object.defineProperty(contacts, data[key].address, {
value: {
"000": {
"body": data[key].body,
"date": date
}
}
});
}
}
}
return contacts;
}
);
}
EDIT 2 : I call my function like that, but my for in loop is still not executed , although my variable seems correctly loaded.
sms.getAllSMS().then( allSMS => {
console.log('allSMS');
console.log(allSMS);
console.log('then is readed'); // this is readed
for (let key in allSMS) {
console.log(allSMS[key]); // this is not executed
}
}).catch(
error => console.warn("something is wrong")
);
Here's a screenshot of the console ('Object' in the console is allSMS). Next to "Object" there's a little "i" that says : "Value below was just evaluated right now".
回答1:
I suspect sms.getAllSMS returns a promise so you can try the following:
sms.getAllSMS()
.then(
allSMS => {
for (let key in allSMS) {
console.log(allSMS[key]);
}
}
)
.catch(
error=>console.warn("something went wrong, error is:",error)
)
Your getAllSMS does not return anything, make sure it returns a promise:
public getAllSMS(): object {
return new Promise(//return a promise
(resolve,reject)=>{
if (SMS) {
SMS.listSMS(this.filters, function (data) {
resolve(data);//added this, resolve promise
}, function (err) {
console.log('error list sms: ' + err);
reject(err);//added this reject promise
});
}else{
resolve([]);//added this, resolving to empty array?
}
}
).then(
data=>{
let contacts = {};
data.forEach(
item=>{
if ((item.address).length > 7 && (item.address).match("[0-9]+")) {
let date = SMSManager.convertUnixDate(item.date); // on converti le format de date de listSMS
if (contacts.hasOwnProperty(item.address)) {
Object.defineProperty(contacts[item.address], item._id, {
value: {
"body": item.body,
"date": date
}
});
} else {
Object.defineProperty(contacts, item.address, {
value: {
"000": {
"body": item.body,
"date": date
}
}
});
}
};
}
);
return contacts;
}
);
}
回答2:
You fixed the asynchrony problem now by using promises, that looks fine.
The problem with the for
loop not enumerating your properties is that Object.defineProperty does (by default) create non-enumerable properties. Use a simple assignment instead:
let contacts = {};
for (const key in data) {
const address = data[key].address;
if (address.length > 7 && address.match("[0-9]+")) {
const date = SMSManager.convertUnixDate(data[key].date); // on converti le format de date de listSMS
const myid = String(data[key]._id);
if (address in contacts) {
contacts[address][myid] = {
"body": data[key].body,
"date": date
};
} else {
contacts[address] = {
"000": {
"body": data[key].body,
"date": date
}
}
}
}
}
return contacts;
来源:https://stackoverflow.com/questions/49896138/how-to-use-promises-in-javascript