this is my code:
const sendBoardId = async boardId => {
let result;
try {
result = await axios.get(`${fetchConfig.prefix}/game/get_board_by_id`, {
params: {
boardId,
},
});
} catch (e) {
console.log(e);
}
console.log('board:', result.data);
if (result.data == null || result.data.length == 0 || result.data == undefined) {
const BoardData = [];
return BoardData;
}
return result.data;
};
const Board = sendBoardId(1);
console.log('aaa', Board);
export { Board };
In the "aaa" console log I keep getting promise, and only in the promise result I got what I needed,
I want to export the promise result and not all the promise it self.
How should I do it?
To use Promise
const sendBoardId = async (boardId) =>
new Promise(async (resolve, reject) => {
let result;
try {
result = await axios.get(`${fetchConfig.prefix}/game/get_board_by_id`, {
params: {
boardId,
},
});
} catch (e) {
console.log(e);
reject(e);
}
console.log("board:", result.data);
if (
result.data === null ||
result.data.length === 0 ||
result.data === undefined
) {
resolve([]);
}
resolve(result.data);
});
const Board = sendBoardId; // UseLess
console.log("aaa", Board);
export { Board }; // Better to direct export sendBoardId
And use:
import {Board} from "...........";
const xyz = async() =>{
const data = await Board(1);
}
Related
I'm trying to implement my own promise in JavaScript. Below is my class.
const states = {
PENDING: "pending",
FULFILLED: "fulfilled",
REJECTED: "rejected"
}
class MyPromise {
constructor(computation) {
this.state = states.PENDING
this.value = undefined;
this.error = undefined;
this.thenQueue = [];
if(typeof computation === 'function') {
setTimeout(() => {
try {
computation(
this.onFulFilled.bind(this),
this.onReject.bind(this)
);
} catch(ex) {
this.onReject.bind(this);
}
});
}
}
then = (fullfilledFn, catchFn) => {
const promise = new MyPromise();
this.thenQueue.push([promise, fullfilledFn, catchFn]);
if(this.state === states.FULFILLED) {
this.propageFulFilled()
} else if(this.state == states.REJECTED) {
this.propageRejected();
}
}
catch = (catchFn) => {
return this.then(undefined, catchFn);
}
onFulFilled = (value) => {
if(this.state === states.PENDING) {
this.state = states.FULFILLED;
this.value = value;
this.propageFulFilled();
}
}
onReject = (error) => {
if(this.state === states.PENDING) {
this.state = states.REJECTED;
this.error = error;
this.propageRejected();
}
}
propageFulFilled = () => {
for(const [promise, fullFilledFn] of this.thenQueue) {
const result = fullFilledFn(this.value);
if(typeof result === 'MyPromise') {
promise.then(
value => promise.onFulFilled(value),
error => promise.onReject(error)
)
} else {
promise.onFulFilled(result); // final result
}
}
this.thenQueue = [];
}
propageRejected = () => {
for(const [promise, undefined, catchFn] of this.thenQueue) {
const result = catchFn(this.value);
if(typeof result === 'MyPromise') {
promise.then(
value => promise.onFulFilled(value),
error => promise.onReject(error)
)
} else {
promise.onFulFilled(result); // final result
}
}
this.thenQueue = [];
}
}
If I call the code below, it works fine
const testPromise = new MyPromise((resolve, reject) => {
setTimeout(() => resolve(10));
});
const firstCall = testPromise.then((value) => {
console.log(value)
return value+1;
});
However, if I add a second then to my firstCall request as below:
const firstCall = testPromise.then((value) => {
console.log(value)
return value+1;
}).then((newVal) => {
console.log(newVal)
});
I got the error TypeError: Cannot read property 'then' of undefined. Does anyone know why it is happening?
Thanks
Your then function is not returning anything:
then = (fullfilledFn, catchFn) => {
const promise = new MyPromise();
this.thenQueue.push([promise, fullfilledFn, catchFn]);
if(this.state === states.FULFILLED) {
this.propageFulFilled()
} else if(this.state == states.REJECTED) {
this.propageRejected();
}
return promise;
}
I am trying to create a simple custom promise from scratch.
For some reason, then is being executed before the onResolve function is called.
Because of this, the response variable is an empty string.
Where am I going wrong here?
Index.js
import CustomPromise from "./customPromise";
const makeApiCall = () => {
return new CustomPromise((success, failure) => {
setTimeout(() => {
let apiResponse = { statusCode: 200, response: "hello" };
if (apiResponse.statusCode == 200) {
success(apiResponse);
} else {
failure(apiResponse);
}
}, 1000);
});
};
makeApiCall().then(response => {
console.log(response);
});
CustomPromise.js
export default class CustomPromise {
constructor(executorFunc) {
this.onResolve = this.onResolve.bind(this);
this.onReject = this.onReject.bind(this);
this.response = "";
executorFunc(this.onResolve, this.onReject);
}
then(input) {
input(this.response);
}
onResolve(response) {
this.response = response;
}
onReject(input) {
input();
}
}
When calling CustomPromise.then you can see that you are just taking the continuation input and calling it immediately regardless of the state of the promise. I think what you'd want to do is to create a task queue and on resolve, you would go ahead and execute it.
You are missing a few key things as well.
First you need to maintain a state inside the promise so that you know when a promise has been settled. This makes it so that you cant resolve/reject the promise multiple times.
Your reject function probably shouldn't just be executing the input. You typically pass a reason into the rejection which will then execute all catch tasks.
No chaining support. Not sure that was even your goal.
const functionOrNoop = (fn) => {
let result = () => {};
if (typeof fn === "function") {
result = fn;
}
return result;
};
class CustomPromise {
constructor(executor) {
this.queue = [];
this.state = "pending";
this.value = null;
this.reason = null;
executor(this.onResolve, this.onReject);
}
static reject(reason) {
return new CustomPromise((_, reject) => reject(reason));
}
static resolve(value) {
return new CustomPromise((resolve) => resolve(value));
}
then(fn) {
return new CustomPromise((resolve, reject) => {
const resolved = (value) => {
try {
resolve(fn(value))
} catch (e) {
reject(e);
}
};
this.enqueue({
resolved,
rejected: reject
});
});
}
catch (fn) {
return new CustomPromise((resolve, reject) => {
const rejected = (reason) => {
try {
resolve(fn(reason))
} catch (e) {
reject(e);
}
};
this.enqueue({
rejected
});
});
}
onResolve = (value) => {
if (this.state === "pending") {
this.state = "resolved";
this.value = value;
this.finalize();
}
}
onReject = (reason) => {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.finalize();
}
};
enqueue(task) {
if (this.state === "pending") {
this.queue.push(task);
} else {
this.eval(task);
}
}
eval(task) {
if (this.state === "resolved") {
functionOrNoop(task.resolved)(this.value);
} else if (this.state === "rejected") {
functionOrNoop(task.rejected)(this.reason);
}
}
finalize() {
this.queue.forEach((task) => this.eval(task));
this.queue = [];
}
}
const p = CustomPromise.resolve("hello")
p
.then((value) => value.toUpperCase())
.then((value) => `J${value.slice(1)}`)
.then((value) => console.log(value))
p.then((value) => console.log(value));
p
.then(() => {
throw new Error(":(")
})
.catch((e) => console.log(e.message))
.then(() => {
throw new Error(":)")
})
.then(() => console.log("SHOULD NOT CALL!"))
.catch((e) => console.log(e.message));
This is meant to serve as an example(so expect bugs) but it encapsulates some of the things I mentioned above. Promises are really complex and you are missing things like 'microtasking' and tens of thousands of hours to testing, development, and vetting.
I'm trying to remove the then statements from the following piece of code and then replace all the catches with try/catch statements. I'm having some issues knowing what to do with the then statements.
export class WelcomePageContribution implements IWorkbenchContribution {
constructor(
#IInstantiationService instantiationService: IInstantiationService,
#IConfigurationService configurationService: IConfigurationService,
#IEditorService editorService: IEditorService,
#IBackupFileService backupFileService: IBackupFileService,
#IFileService fileService: IFileService,
#IWorkspaceContextService contextService: IWorkspaceContextService,
#ILifecycleService lifecycleService: ILifecycleService,
#ICommandService private readonly commandService: ICommandService,
) {
const enabled = isWelcomePageEnabled(configurationService, contextService);
if (enabled && lifecycleService.startupKind !== StartupKind.ReloadedWindow) {
backupFileService.hasBackups().then(hasBackups => {
const activeEditor = editorService.activeEditor;
if (!activeEditor && !hasBackups) {
const openWithReadme = configurationService.getValue(configurationKey) === 'readme';
if (openWithReadme) {
return Promise.all(contextService.getWorkspace().folders.map(folder => {
const folderUri = folder.uri;
return fileService.resolve(folderUri)
.then(folder => {
const files = folder.children ? folder.children.map(child => child.name) : [];
const file = arrays.find(files.sort(), file => strings.startsWith(file.toLowerCase(), 'readme'));
if (file) {
return joinPath(folderUri, file);
}
return undefined;
}, onUnexpectedError);
})).then(arrays.coalesce)
.then<any>(readmes => {
if (!editorService.activeEditor) {
if (readmes.length) {
const isMarkDown = (readme: URI) => strings.endsWith(readme.path.toLowerCase(), '.md');
return Promise.all([
this.commandService.executeCommand('markdown.showPreview', null, readmes.filter(isMarkDown), { locked: true }),
editorService.openEditors(readmes.filter(readme => !isMarkDown(readme))
.map(readme => ({ resource: readme }))),
]);
} else {
return instantiationService.createInstance(WelcomePage).openEditor();
}
}
return undefined;
});
} else {
return instantiationService.createInstance(WelcomePage).openEditor();
}
}
return undefined;
}).then(undefined, onUnexpectedError);
}
}
}
so that the entire thing reads more like this..
const enabled = await isWelcomePageEnabled(configurationService, contextService);
if (enabled && lifecycleService.startupKind !== StartupKind.ReloadedWindow) {
const hasBackups = await backupFileService.hasBackups();
const activeEditor = editorService.activeEditor;
if (!activeEditor && !hasBackups) {
const openWithReadme = configurationService.getValue(configurationKey) === 'readme';
if (openWithReadme) {
...
It looks like you're on the right track with your second code block. then is called on a promise, so instead of using then you would await the function then was called on, save it to a variable, and then move the code that was in the callback to then below the await at the same indentation level. Whenever you await, you can wrap it in a try/catch and put what would have been in the catch callback inside of the catch block.
So for example
fetchData().then(data => {
console.log(data)
}).catch(err => {
console.error(err)
})
becomes
try {
const data = await fetchData()
console.log(data)
}
catch (err) {
console.error(err)
}
The complication in your example is that the code is in a class constructor, and those can't be async.
I'm having yet another async issue where I'm lost and have no idea where or how to fix it. Forgive my bad naming.
api call to twitch api and returns an array its results.
exports.batchPromiseWrapper = function(arr) {
const filteredMungedDataArr = [];
let promiseBatachArray = arr.map(vod_id => {
var url = `https://api.twitch.tv/kraken/videos/${vod_id.id}/markers`;
var params = { api_version: 5 };
return axios
.get(url, {
params: params,
headers: {
"Client-ID": "xxxxxxxxxxxxxxx"
}
})
.then(res => {
return res.data;
})
.catch(function(error) {
console.log(error);
});
});
return Promise.all(promiseBatachArray)
.then(markers => {
if (markers !== null) {
markers.map(markerObj => {
if (markerObj.markers.game_changes !== null) {
markerObj.markers.game_changes.forEach(gameName => {
if (gameName.label === "Fortnite") {
filteredMungedDataArr.push(markerObj);
}
});
}
});
return filteredMungedDataArr;
}
})
.catch(err => {
if (err.status === 500 || err.status === 404) {
console.log("error: ", err, err.message);
}
});
};
The data looks like this:
[[1,2,3,4,5],[1,2,3,4,5]], generator will yield and make a promise.all call of 5 before pausing 5sec and continuing to the next batch of 5.
exports.batchFetchingGeneratorWrapper = function(generator, batchArray) {
let evalNextValue = generator.next();
let delay = (v, t) => {
return new Promise(resolve => {
setTimeout(resolve.bind(null, v), t);
});
};
if (!evalNextValue.done) {
exports.batchPromiseWrapper(evalNextValue.value).then(data => {
let newBatchArray = batchArray;
if (data !== undefined) {
newBatchArray = batchArray.concat(data);
}
delay(5000).then(() => {
exports.batchFetchingGeneratorWrapper(generator, newBatchArray);
});
});
} else {
console.log("yay done!", batchArray);
return batchArray;
}
};
I'm able to console the results in batchArray from batchFetchingGeneratorWrapper, but I unable to act on it and I know it has something to do with async and how it has yet to be resolved.
promiseDataWrapper
.then(data => {
return gatherData.cleanUpVODData(data);
})
.then(data => {
function* batchFetching(batchArray) {
for (let i = 0; i < batchArray.length; i++) {
yield batchArray[i];
}
}
let batchArrResult = [];
let g = batchFetching(data);
new Promise((resolve, reject) => {
gatherData.batchFetchingGeneratorWrapper(g, batchArrResult);
if (g.done) { // i dont think this works
console.log("batchArrResult 1: ", batchArrResult);
resolve(batchArrResult);
}
}).then(result => console.log("asdfasdf", batchArrResult)); // empty array is returned
});
As far as I can tell, the problem lies chiefly in batchFetchingGeneratorWrapper().
It should be a matter of :
fixing delay()
making appropriate returns to make the recursion work
ensuring that the function returns Promise.
Almost undoubtedly (syntactically) simpler with async/await but here it is with old-fashioned thens :
exports.batchFetchingGeneratorWrapper = function(generator, batchArray) {
let evalNextValue = generator.next();
let delay = (t) => {
return new Promise(resolve => {
setTimeout(resolve, t);
});
};
if (!evalNextValue.done) {
return exports.batchPromiseWrapper(evalNextValue.value).then(data => {
return delay(5000).then(() => {
return exports.batchFetchingGeneratorWrapper(generator, batchArray.concat(data || []));
});
});
} else {
console.log("yay done!", batchArray);
return Promise.resolve(batchArray); // <<< promise wrapped to ensure that batchFetchingGeneratorWrapper() returns Promise
}
};
And chain the batchFetchingGeneratorWrapper() call appropriately :
promiseDataWrapper
.then(data => gatherData.cleanUpVODData(data))
.then(data => {
function* batchFetching(batchArray) {
for (let i = 0; i < batchArray.length; i++) {
yield batchArray[i];
}
}
return gatherData.batchFetchingGeneratorWrapper(batchFetching(data), []).then(batchArrResult => {
console.log('batchArrResult: ', batchArrResult);
return batchArrResult;
});
}).catch(error => {
console.log(error);
});
I have 3 functions and each of them return a promise. How can I assign the response from each promise to a defined object?
This is my code:
const runResponse = {
webAudits: [],
webJourneys: [],
appJourneys: []
};
webAuditsFailures(req)
.then(
appJourneysFailures(req)
)
.then(
webJourneysFailures(req)
).then(
res.status(201).json({ reports: runResponse })
);
This is what I've tried:
webAuditsFailures(req)
.then(
(response) => {
runResponse.webAudits = response
},
appJourneysFailures(req)
)
.then(
(response) => {
runResponse.appJourneys = response
},
webJourneysFailures(req)
).then(
(response) => {
runResponse.webJourneys = response
},
res.status(201).json({ reports: runResponse })
);
But it doesn't works as expected because the webAuditsFailures is called again even if it didn't end and I don't understand why...
These are other failed attempts to fix this:
Using await
const webAudits = await webAuditsFailures(req);
const appJourneys = await appJourneysFailures(req);
const webJourneys = await webJourneysFailures(req);
runResponse.webAudits = webAudits;
runResponse.webJourneys = webJourneys;
runResponse.appJourneys = appJourneys;
The same thing happens with this:
const webAudits = await webAuditsFailures(req);
runResponse.webAudits = webAudits;
Using the co module:
co(function* () {
var runResponse = yield {
webAudits: webAuditsFailures(req),
webJourneys: appJourneysFailures(req),
appJourneys: webJourneysFailures(req)
};
res.status(201).json({ reports: runResponse });
});
Using Promise.all:
Promise.all([webAuditsFailures(req), appJourneysFailures(req),
webJourneysFailures(req)])
.then(function(allData) {
res.status(201).json({ reports: allData });
});
This is the webAuditsFailures function, which sequentially calls another functions that return a promise
export default async (req) => {
const report = req.body.webAudits;
const def = deferred();
if(report.length > 0) {
var reportList = [];
for(const [reportIndex, item] of report.entries()) {
for(const [runIndex, run] of item.runs.entries()) {
const result = await waComplianceBusiness(req, run.id);
var failureList = [];
if(result.data.overviews) {
const compliance = result.data.overviews[0].compliance;
if(compliance) {
for(const [index, rule] of compliance.entries()) {
const response = await waRuleOverview(req, run.id, rule.id);
const failedConditions = response.data.failedConditions;
const ruleName = response.data.ruleName;
if(response.data.pagesFailed > 0) {
for(const [condIndex, condition] of failedConditions.entries()) {
const request = {
itemId: condition.conditionResult.id,
itemType: condition.conditionResult.idType,
parentId: condition.conditionResult.parentId,
parentType: condition.conditionResult.parentType
}
const body = {
runId: run.id,
ruleId: rule.id,
payload: request
}
waConditionOverview(req, body).done(response => {
// do stuff here
});
}
}
}
if(failureList.length > 0) {
item.runs[runIndex].failures = failureList;
}
}
}
}
}
def.resolve(report);
return def.promise
}
else {
return [];
}
}
This is the problem:
waConditionOverview(req, body).done(response => {
// do stuff here
});
You're performing an async action but not waiting for the result. Don't use the deferred model - use util.promisify for callbacks.
In addition, I warmly recommend not mutating the request/resposne like this but storing the information in objects and returning those.
Here is how you'd write the code:
export default async (req) => {
const report = req.body.webAudits;
if(report.length === 0) return;
const runs = Array.from(report.entries(), ([i, item]) => item.runs.entries());
for (const [_, run] of runs) {
const result = await waComplianceBusiness(req, run.id);
var failureList = [];
if (!result.data.overviews) {
continue;
}
const compliance = result.data.overviews[0].compliance;
if(!compliance) {
continue;
}
for(const [_, rule] of compliance.entries()) {
const response = await waRuleOverview(req, run.id, rule.id);
const { failedConditions, ruleName} = response.data;
if(failureList.length > 0) {
item.runs[runIndex].failures = failureList;
}
if(response.data.pagesFailed === 0) continue;
for(const [_, condition] of failedConditions.entries()) {
const request = {
itemId: condition.conditionResult.id,
itemType: condition.conditionResult.idType,
parentId: condition.conditionResult.parentId,
parentType: condition.conditionResult.parentType
}
const body = { runId: run.id, ruleId: rule.id, payload: request}
const reponse = await waConditionOverview(req, body);
// do stuff here
// update response
// update report, so next time we try it's updated and doesn't return empty;
}
}
}
return report;
}
In a promise chain, the current .then() should return a promise. The result of this promise will be passed to the next .then():
webAuditsFailures(req)
.then((response) => {
runResponse.webAudits = response;
return appJourneysFailures(req); // return a promise
})
.then((response) => { // response contains the result of the promise
runResponse.appJourneys = response;
return webJourneysFailures(req);
})
.then((response) => {
runResponse.webJourneys = response;
res.status(201).json({ reports: runResponse });
});
Depending on what .json() in the last .then() does, you should return that as well if there are other .then()s in the promise chain.