Promise.then() but functions run async - javascript

I'm new to Javascript and doing a crawler, I've created 4 Promise as these
var openConfig = new Promise((resolve, reject) => {
fs.readFile('./config.json', (err, data) => {
if (err) throw err;
config = JSON.parse(data);
client = new MsTranslator({
client_id: config.translatorId,
client_secret: config.translatorSecret
}, true)
resolve();
})
})
var openFile = new Promise((resolve, reject) => {
console.log('Opening file...')
fs.readFile('./writing/writing.json', (err, data) => {
if (err) throw err;
writing = JSON.parse(data);
console.log('Done parsing file');
resolve();
})
})
var ask = new Promise((resolve, reject) => {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('Which lesson do you want to add? ', (ans) => {
lessonId = ans;
rl.close();
resolve();
})
})
var createLesson = new Promise((resolve, reject) => {
console.log('Now processing lesson ' + lessonId);
})
then call the first Promise
openConfig
.then(() => {
return openFile;
})
.then(() => {
return ask;
})
.then(() => {
return createLesson;
})
but as I run, the console show
Opening file...
Which lesson do you want to add? Now processing lesson undefined
Done parsing file
which I understood as my promises are wrong and my function run async. Can you help me to fix this?
Thank you.

Promises are not "called". In your then chain, you only sequentially await them - but the tasks were already started when you created the promises. If you want to sequence the actions, put them in functions.
Btw, your code contains multiple typical mistakes. Don't use global variables, and always promisify at the lowest possible level:
function openFile(path) {
return new Promise((resolve, reject) => {
fs.readFile('./config.json', (err, data) => {
if (err) reject(err); // never `throw err` in non-promise callbacks!
else resolve(data);
});
});
}
function openJSON(path) {
return openFile(path).then(JSON.parse);
}
function openConfig(path) {
return openJSON(path).then(config =>
new MsTranslator({
client_id: config.translatorId,
client_secret: config.translatorSecret
}, true)
)
}
function ask(question) {
return new Promise((resolve, reject) => {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question(question, ans => {
rl.close();
resolve(ans); // always resolve to *something*
});
});
}
readConfig('./config.json')
.then(client => {
console.log('Opening file...')
return openJSON('./writing/writing.json');
})
.then(writing => {
console.log('Done parsing file');
return ask('Which lesson do you want to add? ');
})
.then(lessonId => {
console.log('Now processing lesson ' + lessonId);
});

Instead of assigning new Promises to vars (these run as soon as created), you should wrap them into functions, which in turn return a new Promise
To help you understand here's a simplified example:
function p1 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {a:1}));
});
}
function p2 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {b:2}));
});
}
function p3 (data) {
return new Promise(function (resolve, reject) {
resolve(Object.assign(data, {c:3}));
});
}
p1({z:0})
.then(p2)
.then(p3)
.then((data)=>console.log(data))
This results in { z: 0, a: 1, b: 2, c: 3 }
See here if you wish to experiment a bit with the above: https://repl.it/DwNB/0
On a separate note, if you are using promises, you should also handle errors in the chain in a final .catch() instead of synchronously throwing midway. That's what the reject callback is for!

Related

Put Javascript Promise into Functions

I have two promises that I am resolving with promise.all:
var mictest1 = new Promise((resolve, reject) => {
resolve(true);
});
var mictest2 = new Promise((resolve, reject) => {
resolve(true);
});
Promise.all([mictest1, mictest2]).then(data => {
console.log("test passed: " + data);
})
I would like to put the promises mictest1 and mictest2 into a function called mictest() so it does the following:
mictest();
Promise.all([mictest1, mictest2]).then(data => {
console.log("test passed: " + data);
})
In this way I can call the function at will, and when the promises get complicated, i don't have that block of text in front of promise.all
Maybe you're looking for the mictest function to return the Promise.all?
const mictest = () => {
var mictest1 = new Promise((resolve, reject) => {
resolve(true);
});
var mictest2 = new Promise((resolve, reject) => {
resolve(true);
});
return Promise.all([mictest1, mictest2]);
};
mictest().then((data) => {
console.log('test passed:', data);
});
I think you are looking for a function that returns the promise:
function mictest() {
return new Promise((resolve, reject) => {
resolve(true);
});
}
You'd use it like
var mictest1 = mictest();
var mictest2 = mictest();
Promise.all([mictest1, mictest2]).then(data => {
console.log("test passed: " + data);
})
or simply
Promise.all([mictest(), mictest()]).then(data => {
console.log("test passed: " + data);
})
Not quite the way you imagined it but you can get very close:
let promises = mictest();
Promise.all(promises).then(data => {
console.log("test passed: " + data);
})
That's just changing two lines of your imagined code. The implementation is simple:
function mictest () {
return [
new Promise((resolve, reject) => {
resolve(true);
}),
new Promise((resolve, reject) => {
resolve(true);
})
]
}
A promise is a value just like strings, numbers, arrays etc. You can treat it like any value. It just happens to be an object that has a .then() method and is awaitable
Note: actually, any object with a .then() method is awaitable even your own custom created non-promise object (actually any object with a .then() method is a promise even though it is not a Promise)

What is the proper way to use Promise.reject with javascript

I have this following piece of code
new Promise((resolve, reject) => {
resolve(apiRequest(data))
reject(console.log('Error'))
}).then(response)
Both methods (resolve and reject) are being fired but I want to call reject only when something goes wrong.
How can I throw an error if something goes wrong on that case?
I checked that but it seems like I can not use an If statement to do that check.
new Promise((resolve, reject) => {
const printResult = apiRequest(data)
console.log(printResult) //Outputs Promise {<pending>}
resolve(printResult) //Then it works
reject(console.log('Error'))
}).then(response)
What would be the correct approach to reject a promise?
The easiest way would be with an if condition. i.e
new Promise((resolve, reject) => {
// do something...
if(somethingGoodHappened) {
resolve(data)
} else {
reject(error)
}
})
But usually when dealing with async requests, the thing you are calling will often be returning a promise, so you can attach the then and catch callbacks there.
apiRequest(data)
.then((result) => {
// all good
})
.catch((err) => {
console.log(err)
})
const mock_api = () => new Promise((res, rej) => {
const number = Math.floor((Math.random() * 100) + 1);
setTimeout(() => {
if (number%2==0) return res('randomly RESOLVED')
return rej('randomly REJECTED')
}, 2000)
})
const async_promise = () => new Promise(async (resolve, reject) => {
try {
const resolvedPromise = await mock_api()
resolve(resolvedPromise)
} catch (e) {
reject(e)
}
})
const classicPromise = () => new Promise((resolve, reject) => {
mock_api()
.then(resolve)
.catch(reject)
})
const makeAsyncRequest = async () => {
try {
const data = await async_promise()
console.log('ASYNC AWAIT RESOLVE', data)
} catch (e) {
console.log('ASYNC AWAIT ERR', e)
}
}
makeAsyncRequest()
classicPromise()
.then(r => console.log('PROMISE CHAIN RESOLVE', r))
.catch(e => console.log('PROMISE CHAIN ERR', e))
Because of you resolve before reject so it cannot run into reject,
You can use:
if (printResult) {
resolve(printResult)
} else {
reject(console.log('Error'))
}
You can catch exceptions and return them as rejected Promises
function asyncFunc() {
try {
doSomethingSync();
return doSomethingAsync()
.then(result => {
ยทยทยท
});
} catch (err) {
return Promise.reject(err);
}
}
Always check for err if there is any err return a promise (example below)
// Return new promise
return new Promise(function(resolve, reject) {
// Do async job
request.get(options, function(err, resp, body) {
if (err) {
reject(err);
} else {
resolve(JSON.parse(body));
}
})
})

Get Object from Object Group javascript

I am getting the below result where I'm looping something.
But I'm unable to get the [["PromiseValue"]] object.
Anyone please help me to do this.
Update :
Code I used for it.
function list(dir) {
const walk = entry => {
return new Promise((resolve, reject) => {
fs.exists(entry, exists => {
if (!exists) {
return resolve({});
}
return resolve(new Promise((resolve, reject) => {
fs.lstat(entry, (err, stats) => {
if (err) {
return reject(err);
}
if (!stats.isDirectory()) {
return resolve({
// path: entry,
// type: 'file',
name: path.basename(entry),
time: stats.mtime,
size: stats.size
});
}
resolve(new Promise((resolve, reject) => {
fs.readdir(entry, (err, files) => {
if (err) {
return reject(err);
}
Promise.all(files.map(child => walk(path.join(entry, child)))).then(children => {
resolve({
// path: entry,
// type: 'folder',
name: path.basename(entry),
time: stats.mtime,
entries: children
});
}).catch(err => {
reject(err);
});
});
}));
});
}));
});
});
}
return walk(dir);
}
This is the code I used to convert the folder Structure to JSON Object.
But, this one gives the above result and I couldn't get the output form it.
You can get the [["PromiseValue"]] by using a callback function
var promise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
promise1.then(function(promiseVal){
console.log('[[PromiseValue]]',promiseVal)
})
More details about Promise here
Yes, I get the Answer.
First I store the value into temp1 in console(I know it does't matter at all).
And use the below code.
var promise1 = Promise.resolve(temp1);
promise1.then(function(value) {
console.log(value);
});
It gives the Below result what i want.

How to pass a variable from a Request as the return value of the global function js

Hello and thank you in advance. I'm using npm tedious package to interact with a database. I'm also using Meteor.call and methods, for which I need to pass a variable (newdata in the example below) that carries the data taken from the database as the return value of the function "rr", so that I would be able to use the result of the function in the client by a Meteor call.
function rr(){
var newdata = [];
var ahora = new Request("SELECT * FROM prueba", function (err) {
if (err) {
console.log("err1");
} else {
}
})
ahora.on('row', function(columns) {
columns.forEach(function(column) {
newdata.push(column.value);
});
});
}
I want "newdata" to be the result of the rr function. How can I do that? If I write "return newdata" it's undefined, I can't use await because newdata is not the return value of any function...
Thank you very much.
Tedious doesn't seem to support promises natively, but you can wrap your function in a promise:
function rr() {
return new Promise((resolve, reject) => {
var ahora = new Request("SELECT * FROM prueba", function (err) {
if (err) {
reject(err);
}
});
var newdata = [];
ahora.on('row', function(columns) {
columns.forEach(function(column) {
newdata.push(column.value);
});
});
resolve(newdata);
}
}
Or slightly shorter:
function rr() {
return new Promise((resolve, reject) => {
new Request("SELECT * FROM prueba")
.on("error", reject)
.on("row", function(columns) {
resolve(columns.map(column => column.value))
});
}
}
If you'd rather not make promises manually, you can try Bluebird's promisify function. I also found a tedious-specific promisifying package tedious-promises, but it doesn't seem to be properly maintained.
You could do something like this:
function rr(){
return await new Promise((resolve, reject) => {
new Request("SELECT * FROM prueba", (err, rowCount) => {err && reject(err);})
.on('row', columns => resolve(columns.map(c => c.value)));
});
}

Promise do not bubble outside

I need to test function testMe using Mocha. But there is trouble when my unit test throw an error. Here is simpified example
function testMe(callback) {
new Promise((resolve, reject) => {
setTimeout(() => resolve([1,2,3]), 1000);
}).then((result) => {
callback(null, result);
}).catch((error) => {
callback(error, null)
});
}
testMe((err, result) => {
if(err) throw new Error();
if(result.length < 5) throw new Error();
});
In this example after throw runs catch block. But I need to run catch block only after reject.
EDIT:
In this case the script never stop. I don't understand why.
function testMe(callback) {
new Promise((resolve, reject) => {
setTimeout(() => resolve([1,2,3]), 1000);
}).then((result) => {
callback(null, result);
}, (error) => {
callback(error, null)
}).catch(() => {
console.log('Do not throw an error but still running');
});
}
testMe((err, result) => {
if(err) throw new Error();
if(result.length < 5) throw new Error();
});
When you work with promises then return the promises from functions instead of taking callbacks.
For example, instead of:
function testMe(callback) {
new Promise((resolve, reject) => {
// ...
});
}
use:
function testMe(callback) {
return new Promise((resolve, reject) => {
// ...
});
}
that way you will have the promise available to the caller of the function.
If you need to mix both styles, i.e. returning promises and taking callbacks, consider using a reliable library to handle that for you especially if you have trouble coding the translation between those style yourself:
http://bluebirdjs.com/docs/api/ascallback.html
http://bluebirdjs.com/docs/api/promise.promisify.html
You can simply return the promise from the test:
function testMe() {
// ^^ drop the callback
return new Promise((resolve, reject) => {
// ^^^^^^ return the promise
setTimeout(() => resolve([1,2,3]), 1000);
});
}
var p = testMe().then(result) => {
// ^^^^^ use the promise
if(result.length < 5) throw new Error();
});
return p; // to mocha

Categories

Resources