JavaScript recursion returning a promise never resolving - javascript

In JavaScript, I have an array of objects being some tasks to do. I iterate through this array with a for loop with await, calling a function doOneTask with returns a Promise.
That works pretty well as long as the code inside doOneTask works as expected. However, those things often fail. Trying again helps almost all the time. So, I'd like to implement a procedure for auto-retrying inside the JavaScript code.
My idea was a recursive function: In case of a failure, doOneTask call itself till the promise if finally resolved.
My code looks like this:
var tasks = [{label: 'task0'},{label: 'task1'},{label: 'task2'}];
async function mainFunction() {
for(let k = 0; k < tasks.length; k++) {
await doOneTask(tasks[k]);
console.log("doOneTask done for index " + k);
}
console.log("End reached!");
}
function doOneTask(task) {
return new Promise(async function (resolve,reject) {
console.log("Starting with: " + task.label);
let checkIfDoeSomeStuffWorked = await doSomeAsyncStuff();
if(checkIfDoeSomeStuffWorked == false) {
console.log(task.label + ": FAILED");
return doOneTask(task);
}
else {
console.log(task.label + ": SUCCESS");
resolve(true);
}
});
}
function doSomeAsyncStuff() {
return new Promise(function (resolve,reject) {
var myRandom = Math.random();
if(myRandom < 0.3) {
resolve(true);
}
else {
resolve(false);
}
});
}
mainFunction();
(In real life, doSomeAsyncStuff is a backend call which often fails. The random() part is just for demonstration. In reality, I also limit the number of trials, before stopping the script.)
However, it doesn't work. In case of a failure, the script stops after having reached the SUCCESS console log. I never get back to the loop and the next items in the loop never get executed.

You have no use for the q library dependency. async functions always return a Promise, so you can simplify your code quite a bit -
async function doOneTask (task) {
const result = await doSomeAsyncStuff()
if (result === false) {
console.log(`${task} failed`)
return doOneTask(task)
}
else {
console.log(`${task} passed`)
return true
}
}
Your fake function doSomeAsyncStuff can be cleaned up too -
async function doSomeAsyncStuff () {
return Math.random() < 0.3
}
But let's add a fake delay of 1 second so that we can show things working 100% -
async function doSomeAsyncStuff () {
return new Promise(resolve =>
setTimeout(resolve, 1000, Math.random() < 0.3)
)
}
Last, your main function uses a really old looping convention. As you're using modern JavaScript, you might as well use for-of syntax -
async function main (tasks = []) {
for (const t of tasks) {
await doOneTask(t)
}
return "done"
}
Finally we run the program -
const tasks =
[ 'task0', 'task1', 'task2' ]
main(tasks).then(console.log, console.error)
// task0 failed
// task0 passed
// task1 failed
// task1 failed
// task1 passed
// task2 passed
// done
Expand the snippet below to verify the results in your own browser -
async function doOneTask (task) {
const result = await doSomeAsyncStuff()
if (result === false) {
console.log(`${task} failed`)
return doOneTask(task)
}
else {
console.log(`${task} passed`)
return true
}
}
async function doSomeAsyncStuff () {
return new Promise(resolve =>
setTimeout(resolve, 1000, Math.random() < 0.3)
)
}
async function main (tasks = []) {
for (const t of tasks) {
await doOneTask(t)
}
return "done"
}
const tasks =
[ 'task0', 'task1', 'task2' ]
main(tasks).then(console.log, console.error)
// task0 failed
// task0 passed
// task1 failed
// task1 failed
// task1 passed
// task2 passed
// done

After having completed the question, but just before posting, something came into my mind: In the setup above, I don't resolve the very same promise object when I finally reach success, but for each function call a new promise object is generated. My solution/workaround is quite simple: use q the promise library passing the promise from one function call to the next function call:
var q = require('q');
async function doOneTask(task,promiseObj) {
if(!promiseObj) {
var promiseObj = q.defer();
}
console.log("Starting with: " + task.label);
let checkIfDoeSomeStuffWorked = await doSomeAsyncStuff();
if(checkIfDoeSomeStuffWorked == false) {
console.log(task.label + ": FAILED");
return doOneTask(task,promiseObj);
}
else {
console.log(task.label + ": SUCCESS");
promiseObj.resolve(true);
}
return promiseObj.promise;
}
That way, we make sure that the very same promise object which is generated at the first call of doOneTask is resolved in the end - event after the 20th execution.

Related

Closure not updating inside a while loop in Javascript

I'm trying to get a closure to return a value that is supposed to be updated once a promise is resolved (or rejected).
The following code works. Initially the internal variable from within the close returns NONE as expected.
Then the first Promise is launched, and once that is resolved, the internal variable is updated to FAIL.
The second Promise is a deliberate delay, just so that we can observe the change of the closured variable.
However, once the while loop is added to the equation, by uncommenting that loop(x) section, the update is not observable within the while loop.
I would expect to see this:
...
9963000000 NONE
9964000000 NONE
9965000000 NONE
9966000000 NONE
9967000000 NONE
9968000000 FAIL
9969000000 FAIL
9970000000 FAIL
9971000000 FAIL
9972000000 FAIL
9973000000 FAIL
9974000000 FAIL
...
I know it might be due to the single threaded blocking, but, is there a way to observe a dynamic external variable from within the while loop?
let sleep = async (ms) => new Promise ((resolve, reject) => setTimeout (resolve, ms));
let task = async (ms) => new Promise (function(resolve, reject) {
setTimeout (function(){
const error = true;
let result;
if(error){
result = '_NO_';
reject({'state': false, 'response': result});
}else{
result = '_YES_';
resolve({'state': true, 'response': result});
}
}, ms);
});
let loop = async (cb) => {
let i = 0;
while(i<10000000000){
const value = cb.getResponse();
(function() {
if(i%1000000==0){ console.log(i, value) };
i += 1;
})(i, value);
}
}
const linkResponse = (function(){
let response = 'NONE';
function setResponse(value) {response = value; return response};
function getResponse() {return response};
return { 'setResponse': setResponse, 'getResponse': getResponse };
});
const x = linkResponse();
console.log(x.getResponse());
(async () => {
task(3000)
.then(function(res){
console.log('__OK__', res);
let response = 'SUCCESS';
x.setResponse(response)
})
.catch(function(err){
console.log('error', err);
let response = 'FAIL';
x.setResponse(response)
});
sleep(6000)
.then(function(res){
console.log(x.getResponse())
});
//loop(x);
})();
Well, thanks for the help. Just as I was suspecting, it is indeed a blocked thread issue. I solved the problem with a recursive function. I just needed to have a long process running in the background and I naively thought that an infinite loop will do the job.
let loop2 = function(i, cb) {
if(i>100000){
return
}
console.log(i, cb.getResponse());
i += 1;
sleep(0)
.then(function(res){
loop2(i, cb);
});
}
And then calling:
loop2(0, x);

Can we make promise to wait until resolved and onreject call back the promise again

I'm learning about Promise's and have a little doubt assuming that I want to get resolved status out of Promises
and not want reject! Can I just call back the promise function inside
catch to make sure that I get only approved value! Is that possible or
will it throw an error or goes to loop iteration
let promisetocleantheroom = new Promise(function cleanroom(resolve, reject) {
//code to clean the room
//then as a result the clean variable will have true or flase
if (clean == "true") {
resolve("cleaned");
} else {
reject("not cleaned");
}
});
promisetocleantheroom.then(function cleanroom(fromResolve) {
// wait for the function to finish only then it would run the function then
console.log("the room is " + fromResolve);
}).catch(function cleanroom(fromReject) {
//calling back the promise again
cleanroom();
});
If you don't mind having higher order functions and recursivity, here is my proposed solution.
First you need to wrap your promise in a function to recreate it when it fails. Then you can pass it to retryPromiseMaker with a partial error handler to create another function that will act as retrier. And this function will return a Promise that will fulfill only if one of the inner promises fulfills.
Sounds complicated but I promise you it is not!
const retryPromiseMaker = (fn, errorfn = null) => {
const retryPromise = (retries = 3, err = null) => {
if (err) {
errorfn(err);
}
if (retries === 0) {
return Promise.reject(err);
}
return fn()
.catch(err => retryPromise(retries - 1, err));
};
return retryPromise;
}
const cleanTheRoom = (resolve, reject) => {
// simulate cleaning as a probability of 33%
const clean = Math.random() < 0.33;
setTimeout(() => {
if (clean) {
resolve("cleaned");
} else {
reject("not cleaned");
}
}, Math.random() * 700 + 200);
};
const promiseToCleanTheRoom = () => new Promise(cleanTheRoom);
const logStatus = end => value => {
let text = '';
if (end){
text += "at the end ";
}
text += "the room is " + value;
console.log(text);
};
retryPromiseMaker(promiseToCleanTheRoom, logStatus(false))(4)
.then(logStatus(true),logStatus(true));

Synchronize multiple Promises while allowing multiple number of retries

I am trying to build a downloader that automatically retries downloading. Basically, a task queue which retries tasks for a certain number of times. I first tried using Promise.all() but the "trick" to circumvent the fail-on-first-reject described here did not help (and is an anti-pattern as described further down in that thread)
So I got a version working which seems to somewhat do what I want. At least the results it prints are correct. But it still throws several uncaught exception test X errors/warnings and I don't know what to do about that.
The Code:
asd = async () => {
// Function simulating tasks which might fail.
function wait(ms, data) {
return new Promise( (resolve, reject) => setTimeout(() => {
if (Math.random() > 0.5){
resolve(data);
} else {
reject(data);
}
}, ms) );
}
let tasks = [];
const results = [];
// start the tasks
for ( let i = 0; i < 20; i++) {
const prom = wait(100 * i, 'test ' + i);
tasks.push([i, prom]);
}
// collect results and handle retries.
for ( let tries = 0; tries < 10; tries++){
failedTasks = [];
for ( let i = 0; i < tasks.length; i++) {
const task_idx = tasks[i][0];
// Wait for the task and check whether they failed or not.
// Any pointers on how to improve the readability of the next 6 lines appreciated.
await tasks[i][1].then(result => {
results.push([task_idx, result])
}).catch(err => {
const prom = wait(100 * task_idx, 'test ' + task_idx);
failedTasks.push([task_idx, prom])
});
}
// Retry the tasks which failed.
if (failedTasks.length === 0){
break;
} else {
tasks = failedTasks;
}
console.log('try ', tries);
}
console.log(results);
}
In the end, the results array contains (unless a task failed 10 times) all the results. But still uncaught exceptions fly around.
As not all rejected promises result in uncaught exceptions, my suspicion is, that starting the tasks first and applying then()/catch() later is causing some timing issues here.
Any improvements or better solutions to my problems are appreciated. E.g. my solution only allows retries "in waves". If anyone comes up with a better continuous solution, that would be much appreciated as well.
Using await and asnyc allows to solve that in a much clearer way.
You pass an array of tasks (functions that when executed start the given task) to the execute_tasks. This function will call for each of those tasks the execute_task, passing the task function to it, the execute_task will return a Promise containing the information if the task was successful or not.
The execute_task as a loop that loops until the async task was successful or the maximum number of retries reached.
Because each of the tasks has its own retry loop you can avoid those waves. Each task will queue itself for a new execution as it fails. Using await this way creates some kind of cooperative multitasking. And all errors are handled because the task is executed in a try catch block.
function wait(ms, data) {
return new Promise((resolve, reject) => setTimeout(() => {
if (Math.random() > 0.5) {
resolve(data);
} else {
reject(new Error());
}
}, ms));
}
async function execute_task(task) {
let result, lastError;
let i = 0
//loop until result was found or the retry count is larger then 10
while (!result && i < 10) {
try {
result = await task()
} catch (err) {
lastError = err
// maybe sleep/wait before retry
}
i++
}
if (result) {
return { success: true, data: result }
} else {
return { success: false, err: lastError }
}
}
async function execute_tasks(taskList) {
var taskPromises = taskList.map(task => execute_task(task))
// the result could be sorted into failed and not failed task before returning
return await Promise.all(taskPromises)
}
var taskList = []
for (let i = 0; i < 10; i++) {
taskList.push(() => {
return wait(500, {
foo: i
})
})
}
execute_tasks(taskList)
.then(result => {
console.dir(result)
})

JavaScript: Asynchronous method in while loop

I'm tackling a project that requires me to use JavaScript with an API method call. I'm a Java programmer who has never done web development before so I'm having some trouble with it.
This API method is asynchronous and it's in a while loop. If it returns an empty array, the while loop finishes. Otherwise, it loops. Code:
var done = true;
do
{
async_api_call(
"method.name",
{
// Do stuff.
},
function(result)
{
if(result.error())
{
console.error(result.error());
}
else
{
// Sets the boolean to true if the returned array is empty, or false otherwise.
done = (result.data().length === 0) ? true : false;
}
}
);
} while (!done);
This doesn't work. The loop ends before the value of "done" is updated. I've done some reading up on the subject and it appears I need to use promises or callbacks because the API call is asynchronous, but I can't understand how to apply them to the code I have above.
Help would be appreciated!
edit: see the bottom, there is the real answer.
I encourage you yo use the Promise API. Your problem can be solved using a Promise.all call:
let promises = [];
while(something){
promises.push(new Promise((r, j) => {
YourAsyncCall(() => r());
});
}
//Then this returns a promise that will resolve when ALL are so.
Promise.all(promises).then(() => {
//All operations done
});
The syntax is in es6, here is the es5 equivalent (Promise API may be included externally):
var promises = [];
while(something){
promises.push(new Promise(function(r, j){
YourAsyncCall(function(){ r(); });
});
}
//Then this returns a promise that will resolve when ALL are so.
Promise.all(promises).then(function(){
//All operations done
});
You can also make your api call return the promise and push it directly to the promise array.
If you don't want to edit the api_call_method you can always wrap your code in a new promise and call the method resolve when it finishes.
edit: I have seen now the point of your code, sorry. I've just realized that Promise.all will not solve the problem.
You shall put what you posted (excluding the while loop and the control value) inside a function, and depending on the condition calling it again.
Then, all can be wraped inside a promise in order to make the external code aware of this asynchronous execution. I'll post some sample code later with my PC.
So the good answer
You can use a promise to control the flow of your application and use recursion instead of the while loop:
function asyncOp(resolve, reject) {
//If you're using NodeJS you can use Es6 syntax:
async_api_call("method.name", {}, (result) => {
if(result.error()) {
console.error(result.error());
reject(result.error()); //You can reject the promise, this is optional.
} else {
//If your operation succeeds, resolve the promise and don't call again.
if (result.data().length === 0) {
asyncOp(resolve); //Try again
} else {
resolve(result); //Resolve the promise, pass the result.
}
}
});
}
new Promise((r, j) => {
asyncOp(r, j);
}).then((result) => {
//This will call if your algorithm succeeds!
});
/*
* Please note that "(...) => {}" equivals to "function(...){}"
*/
sigmasoldier's solution is correct, just wanted to share the ES6 version with async / await:
const asyncFunction = (t) => new Promise(resolve => setTimeout(resolve, t));
const getData = async (resolve, reject, count) => {
console.log('waiting');
await asyncFunction(3000);
console.log('finshed waiting');
count++;
if (count < 2) {
getData(resolve, reject, count);
} else {
return resolve();
}
}
const runScript = async () => {
await new Promise((r, j) => getData(r, j, 0));
console.log('finished');
};
runScript();
If you don't want to use recursion you can change your while loop into a for of loop and use a generator function for maintaining done state. Here's a simple example where the for of loop will wait for the async function until we've had 5 iterations and then done is flipped to true. You should be able to update this concept to set your done variable to true when your webservice calls have buffered all of your data rows.
let done = false;
let count = 0;
const whileGenerator = function* () {
while (!done) {
yield count;
}
};
const asyncFunction = async function(){
await new Promise(resolve => { setTimeout(resolve); });
};
const main = new Promise(async (resolve)=>{
for (let i of whileGenerator()){
console.log(i);
await asyncFunction();
count++;
if (count === 5){
done = true;
}
}
resolve();
});
main.then(()=>{
console.log('all done!');
});
Also you may try recursion solution.
function asyncCall(cb) {
// Some async operation
}
function responseHandler(result) {
if (result.error()) {
console.error(result.error());
} else if(result.data() && result.data().length) {
asyncCall(responseHandler);
}
}
asyncCall(responseHandler);
Here is a solution I came up with. Place this in an async function.
let finished = false;
const loop = async () => {
return new Promise(async (resolve, reject) => {
const inner = async () => {
if (!finished) {
//insert loop code here
if (xxx is done) { //insert this in your loop code after task is complete
finshed = true;
resolve();
} else {
return inner();
}
}
}
await inner();
})
}
await loop();
If you don't want to use Promises you can restructure your code like so:
var tasks = [];
var index = 0;
function processNextTask()
{
if(++index == tasks.length)
{
// no more tasks
return;
}
async_api_call(
"method.name",
{
// Do stuff.
},
function(result)
{
if(result.error())
{
console.error(result.error());
}
else
{
// process data
setTimeout(processNextTask);
}
}
);
}
Your loop won't work, because it is sync, your async task is async, so the loop will finish before the async task can even respond. I'd reccomend you to use Promises to manage async tasks:
//first wrapping your API into a promise
var async_api_call_promise = function(methodName, someObject){
return new Promise((resolve, reject) => {
async_api_call(methodName, someObject, function(result){
if(result.error()){
reject( result.error() )
}else{
resolve( result.data() )
}
});
})
}
now to your polling code:
//a local utility because I don't want to repeat myself
var poll = () => async_api_call_promise("method.name", {/*Do stuff.*/});
//your pulling operation
poll().then(
data => data.length === 0 || poll(), //true || tryAgain
err => {
console.error(err);
return poll();
}
).then((done) => {
//done === true
//here you put the code that has to wait for your "loop" to finish
});
Why Promises? Because they do state-management of async operations. Why implement that yourself?
let taskPool = new Promise(function(resolve, reject) {
resolve("Success!");
});
let that = this;
while (index < this.totalPieces) {
end = start + thisPartSize;
if (end > filesize) {
end = filesize;
thisPartSize = filesize - start;
}
taskPool.then(() => {
that.worker(start, end, index, thisPartSize);
});
index++;
start = end;
}

How do I access <state> and <value> properties of a Promise? [duplicate]

I have a pure JavaScript Promise (built-in implementation or poly-fill):
var promise = new Promise(function (resolve, reject) { /* ... */ });
From the specification, a Promise can be one of:
'settled' and 'resolved'
'settled' and 'rejected'
'pending'
I have a use case where I wish to interrogate the Promise synchronously and determine:
is the Promise settled?
if so, is the Promise resolved?
I know that I can use #then() to schedule work to be performed asynchronously after the Promise changes state. I am NOT asking how to do this.
This question is specifically about synchronous interrogation of a Promise's state. How can I achieve this?
No such synchronous inspection API exists for native JavaScript promises. It is impossible to do this with native promises. The specification does not specify such a method.
Userland libraries can do this, and if you're targeting a specific engine (like v8) and have access to platform code (that is, you can write code in core) then you can use specific tools (like private symbols) to achieve this. That's super specific though and not in userland.
Nope, no sync API, but here's my version of the async promiseState (with help from #Matthijs):
function promiseState(p) {
const t = {};
return Promise.race([p, t])
.then(v => (v === t)? "pending" : "fulfilled", () => "rejected");
}
var a = Promise.resolve();
var b = Promise.reject();
var c = new Promise(() => {});
promiseState(a).then(state => console.log(state)); // fulfilled
promiseState(b).then(state => console.log(state)); // rejected
promiseState(c).then(state => console.log(state)); // pending
promise-status-async does the trick. It is async but it does not use then to wait the promise to be resolved.
const {promiseStatus} = require('promise-status-async');
// ...
if (await promiseStatus(promise) === 'pending') {
const idle = new Promise(function(resolve) {
// can do some IDLE job meanwhile
});
return idle;
}
You can make a race with Promise.resolve
It's not synchronous but happens now
function promiseState(p, isPending, isResolved, isRejected) {
Promise.race([p, Promise.resolve('a value that p should not return')]).then(function(value) {
if (value == 'a value that p should not return') {
(typeof(isPending) === 'function') && isPending();
}else {
(typeof(isResolved) === 'function') && isResolved(value);
}
}, function(reason) {
(typeof(isRejected) === 'function') && isRejected(reason);
});
}
A little script for testing and understand their meaning of asynchronously
var startTime = Date.now() - 100000;//padding trick "100001".slice(1) => 00001
function log(msg) {
console.log((""+(Date.now() - startTime)).slice(1) + ' ' + msg);
return msg;//for chaining promises
};
function prefix(pref) { return function (value) { log(pref + value); return value; };}
function delay(ms) {
return function (value) {
var startTime = Date.now();
while(Date.now() - startTime < ms) {}
return value;//for chaining promises
};
}
setTimeout(log, 0,'timeOut 0 ms');
setTimeout(log, 100,'timeOut 100 ms');
setTimeout(log, 200,'timeOut 200 ms');
var p1 = Promise.resolve('One');
var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "Two"); });
var p3 = Promise.reject("Three");
p3.catch(delay(200)).then(delay(100)).then(prefix('delayed L3 : '));
promiseState(p1, prefix('p1 Is Pending '), prefix('p1 Is Resolved '), prefix('p1 Is Rejected '));
promiseState(p2, prefix('p2 Is Pending '), prefix('p2 Is Resolved '), prefix('p2 Is Rejected '));
promiseState(p3, prefix('p3 Is Pending '), prefix('p3 Is Resolved '), prefix('p3 Is Rejected '));
p1.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p2.then(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
p3.catch(prefix('Level 1 : ')).then(prefix('Level 2 : ')).then(prefix('Level 3 : '));
log('end of promises');
delay(100)();
log('end of script');
results with delay(0) (comment the while in delay)
00001 end of promises
00001 end of script
00001 Level 1 : One
00001 Level 1 : Three
00001 p1 Is Resolved One
00001 p2 Is Pending undefined
00001 p3 Is Rejected Three
00001 Level 2 : One
00001 Level 2 : Three
00001 delayed L3 : Three
00002 Level 3 : One
00002 Level 3 : Three
00006 timeOut 0 ms
00100 timeOut 100 ms
00100 Level 1 : Two
00100 Level 2 : Two
00101 Level 3 : Two
00189 timeOut 200 ms
and the results of this test with firefox(chrome keep the order)
00000 end of promises
00100 end of script
00300 Level 1 : One
00300 Level 1 : Three
00400 p1 Is Resolved One
00400 p2 Is Pending undefined
00400 p3 Is Rejected Three
00400 Level 2 : One
00400 Level 2 : Three
00400 delayed L3 : Three
00400 Level 3 : One
00400 Level 3 : Three
00406 timeOut 0 ms
00406 timeOut 100 ms
00406 timeOut 200 ms
00406 Level 1 : Two
00407 Level 2 : Two
00407 Level 3 : Two
promiseState make .race and .then : Level 2
in node, say undocumented internal process.binding('util').getPromiseDetails(promise)
> process.binding('util').getPromiseDetails(Promise.resolve({data: [1,2,3]}));
[ 1, { data: [ 1, 2, 3 ] } ]
> process.binding('util').getPromiseDetails(Promise.reject(new Error('no')));
[ 2, Error: no ]
> process.binding('util').getPromiseDetails(new Promise((resolve) => {}));
[ 0, <1 empty item> ]
You can use an (ugly) hack in Node.js until a native method is offered:
util = require('util');
var promise1 = new Promise (function (resolve) {
}
var promise2 = new Promise (function (resolve) {
resolve ('foo');
}
state1 = util.inspect (promise1);
state2 = util.inspect (promise2);
if (state1 === 'Promise { <pending> }') {
console.log('pending'); // pending
}
if (state2 === "Promise { 'foo' }") {
console.log ('foo') // foo
}
Updated: 2019
Bluebird.js offers this: http://bluebirdjs.com/docs/api/isfulfilled.html
var Promise = require("bluebird");
let p = Promise.resolve();
console.log(p.isFulfilled());
If you'd prefer to create your own wrapper, here is a nice blog about it.
Because JavaScript is single-threaded, it's hard to find a common enough use case to justify putting this in the spec. The best place to know if a promise is resolved is in .then(). Testing if a Promise is fullfilled would create a polling loop which is most likely the wrong direction.
async/await is a nice construct if you'd like to reason async code synchronously.
await this();
await that();
return 'success!';
Another useful call is Promise.all()
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
When I first reached for this answer, that is the use case I was looking for.
It's indeed quite annoying that this basic functionality is missing. If you're using node.js then I know of two workarounds, neither of 'em very pretty. Both snippets below implement the same API:
> Promise.getInfo( 42 ) // not a promise
{ status: 'fulfilled', value: 42 }
> Promise.getInfo( Promise.resolve(42) ) // fulfilled
{ status: 'fulfilled', value: 42 }
> Promise.getInfo( Promise.reject(42) ) // rejected
{ status: 'rejected', value: 42 }
> Promise.getInfo( p = new Promise(() => {}) ) // unresolved
{ status: 'pending' }
> Promise.getInfo( Promise.resolve(p) ) // resolved but pending
{ status: 'pending' }
There doesn't seem to be any way to distinguish the last two promise states using either trick.
1. Use the V8 debug API
This is the same trick that util.inspect uses.
const Debug = require('vm').runInDebugContext('Debug');
Promise.getInfo = function( arg ) {
let mirror = Debug.MakeMirror( arg, true );
if( ! mirror.isPromise() )
return { status: 'fulfilled', value: arg };
let status = mirror.status();
if( status === 'pending' )
return { status };
if( status === 'resolved' ) // fix terminology fuck-up
status = 'fulfilled';
let value = mirror.promiseValue().value();
return { status, value };
};
2. Synchronously run microtasks
This avoids the debug API, but has some frightening semantics by causing all pending microtasks and process.nextTick callbacks to be run synchronously. It also has the side-effect of preventing the "unhandled promise rejection" error from ever being triggered for the inspected promise.
Promise.getInfo = function( arg ) {
const pending = {};
let status, value;
Promise.race([ arg, pending ]).then(
x => { status = 'fulfilled'; value = x; },
x => { status = 'rejected'; value = x; }
);
process._tickCallback(); // run microtasks right now
if( value === pending )
return { status: 'pending' };
return { status, value };
};
await usage to #jib's answer, with idiomatic prototyping.
Object.defineProperty(Promise.prototype, "state", {
get: function(){
const o = {};
return Promise.race([this, o]).then(
v => v === o ? "pending" : "resolved",
() => "rejected");
}
});
// usage: console.log(await <Your Promise>.state);
(async () => {
console.log(await Promise.resolve(2).state); // "resolved"
console.log(await Promise.reject(0).state); // "rejected"
console.log(await new Promise(()=>{}).state); // "pending"
})();
note that this async function execute "almost" immediately like synced function (or actually possibly be instantly).
You can wrap your promises in this way
function wrapPromise(promise) {
var value, error,
settled = false,
resolved = false,
rejected = false,
p = promise.then(function(v) {
value = v;
settled = true;
resolved = true;
return v;
}, function(err) {
error = err;
settled = true;
rejected = true;
throw err;
});
p.isSettled = function() {
return settled;
};
p.isResolved = function() {
return resolved;
};
p.isRejected = function() {
return rejected;
};
p.value = function() {
return value;
};
p.error = function() {
return error;
};
var pThen = p.then, pCatch = p.catch;
p.then = function(res, rej) {
return wrapPromise(pThen(res, rej));
};
p.catch = function(rej) {
return wrapPromise(pCatch(rej));
};
return p;
}
I looked through the solutions proposed to this question and could not see one that corresponds to a simple approach that I have used in Node.js.
I have defined a simple class PromiseMonitor, which takes a promise as the single parameter to its constructor, and has a string property .status which returns the standard string values corresponding to the promise status, "pending", "resolved" or "rejected", and four boolean properties .pending, .resolved, .rejected and .error. The property .error is set true only if .rejected is true and the reject callback was passed an Error object.
The class simply uses .then() on the promise to change the status of the PromiseMonitor when the promise is resolved or rejected. It does not interfere with any other use of the original promise. Here is the code:
class PromiseMonitor {
constructor(prm){
this._status = "pending";
this._pending = true;
this._resolved = false;
this._rejected = false;
this._error = false;
prm
.then( ()=>{
this._status = "resolved";
this._resolved = true;
this._pending = false;
}
, (err)=>{
this._status = "rejected";
this._pending = false;
this._rejected = true;
this._error = err instanceof Error ? true: false ;
}
);
}
get status(){ return this._status; };
get pending(){ return this._pending; };
get resolved(){ return this._resolved; };
get rejected(){ return this._rejected; };
get error(){ return this._error };
};
To monitor the status of a Promise, simply create an instance of PromiseMonitor, passing the promise in as a parameter, for example:
let promiseObject = functionThatReturnsAPromise();
let promiseMonitor = new PromiseMonitor( promiseObject );
Now you can syncrhonously check all the properties of promiseMonitor, which will track the status of the original promise. Here is a test script that demonstrates the three possible resolutions of a promise being monitored.
let ticks = 0;
let tickerID = setInterval( ()=>{++ticks; console.log(`..tick ${ticks}`)}, 1000);
async function run(){
console.log("Start");
let delay = prmDelay(2000);
let delayMonitor = new PromiseMonitor(delay);
// normal handling of delay promise
delay.then((result)=>( console.log("Normal resolution of delay using .then()") ) );
console.log("delay at start:\n", delay);
console.log("delayMonitor at start:\n", delayMonitor);
await delay;
console.log("delay finished:\n", delay);
console.log("delayMonitor finished:\n", delayMonitor);
console.log("\n\n TEST2: Rejection without an Error test ================================")
let rejDelay = prmDelay(3000, "reject");
let rejMonitor = new PromiseMonitor(rejDelay);
// normal handling of reject result on promise
rejDelay.then((result)=>( console.log("Normal resolution of rejDelay using .then will not happen") )
, (err)=>( console.log("Rejection of rejDelay handled using .then")));
console.log("rejDelay at start:\n", rejDelay);
console.log("rejMonitor at start:\n", rejMonitor);
await rejDelay.catch( (err)=>{ console.log( "Caught error using .catch on rejDelay" ); });
console.log("rejDelay finished:\n", rejDelay);
console.log("rejMonitor finished:\n", rejMonitor);
console.log("\n\n TEST3: Rejection with an Error test ================================")
let errMonitor ;
let errDelay;
try{
errDelay = prmDelay(1000, "error");
errMonitor = new PromiseMonitor(errDelay);
// normal handling of results of the original promise
errDelay.then(
(result)=>{
console.log("Normal expiry of errDelay");
console.log("Monitor Status is " + errMonitor.status )
}
, (err)=>{
console.log("** Rejection of errDelay handled using .then()");
console.log(" Monitor Status is " + errMonitor.status )
}
);
console.log("errDelay at start:\n", errDelay);
console.log("errMonitor at start:\n", errMonitor);
await errDelay;
console.log("**** This should never be run");
} catch(err) {
console.log( "** Caught error on errDelay using try{}catch{}:" );
console.log( " Monitor Status is " + errMonitor.status )
};
console.log("errDelay finished:\n", errDelay);
console.log("errMonitor finished:\n", errMonitor);
clearInterval(tickerID);
}
/**
* Creates a new promise with a specific result
* #param {*} tt
* #param {*} exitType ("resolve", "reject" or "error")
*/
function prmDelay (tt, exitType) {
return new Promise(function(resolve, reject) {
if( exitType == 'reject' ){
setTimeout(()=>{ reject("REJECTED")}, tt);
} else if( exitType== 'error'){
setTimeout(()=>{ reject(new Error( "ERROR Rejection") ); }, tt);
} else {
setTimeout(()=>{ resolve("RESOLVED") }, tt);
} ;
});
};
run();
You can add a method to Promise.prototype. It looks like this:
Edited: The first solution is not working properly, like most of the answers here. It returns "pending" until the asynchronous function ".then" is invoked, which is not happen immediately. (The same is about solutions using Promise.race). My second solution solves this problem.
if (window.Promise) {
Promise.prototype.getState = function () {
if (!this.state) {
this.state = "pending";
var that = this;
this.then(
function (v) {
that.state = "resolved";
return v;
},
function (e) {
that.state = "rejected";
return e;
});
}
return this.state;
};
}
You can use it on any Promise. For exemple:
myPromise = new Promise(myFunction);
console.log(myPromise.getState()); // pending|resolved|rejected
Second (and correct) solution:
if (window.Promise) {
Promise.stateable = function (func) {
var state = "pending";
var pending = true;
var newPromise = new Promise(wrapper);
newPromise.state = state;
return newPromise;
function wrapper(resolve, reject) {
func(res, rej);
function res(e) {
resolve(e);
if (pending) {
if (newPromise)
newPromise.state = "resolved";
else
state = "resolved";
pending = false;
}
}
function rej(e) {
reject(e);
if (pending) {
if (newPromise)
newPromise.state = "rejected";
else
state = "rejected";
pending = false;
}
}
}
};
}
And use it:
Notice: In this solution you doesn't have to use the "new" operator.
myPromise = Promise.stateable(myFunction);
console.log(myPromise.state); // pending|resolved|rejected
Caveat: This method uses undocumented Node.js internals and could be changed without warning.
In Node you can synchronously determine a promise's state using process.binding('util').getPromiseDetails(/* promise */);.
This will return:
[0, ] for pending,
[1, /* value */] for fulfilled, or
[2, /* value */] for rejected.
const pending = new Promise(resolve => setTimeout(() => resolve('yakko')));;
const fulfilled = Promise.resolve('wakko');
const rejected = Promise.reject('dot');
[pending, fulfilled, rejected].forEach(promise => {
console.log(process.binding('util').getPromiseDetails(promise));
});
// pending: [0, ]
// fulfilled: [1, 'wakko']
// rejected: [2, 'dot']
Wrapping this into a helper function:
const getStatus = promise => ['pending', 'fulfilled', 'rejected'][
process.binding('util').getPromiseDetails(promise)[0]
];
getStatus(pending); // pending
getStatus(fulfilled); // fulfilled
getStatus(rejected); // rejected
There's another elegant & hacky way of checking if a promise is still pending just by converting the whole object to string and check it with the help of inspect like this: util.inspect(myPromise).includes("pending").
Tested on Node.js 8,9,10,11,12,13
Here's a full example
const util = require("util")
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async ()=>{
let letmesleep = sleep(3000)
setInterval(()=>{
console.log(util.inspect(letmesleep).includes("pending"))
},1000)
})()
Result:
true
true
false
false
false
what you can do, is to use a variable to store the state, manually set the state to that variable, and check that variable.
var state = 'pending';
new Promise(function(ff, rjc) {
//do something async
if () {//if success
state = 'resolved';
ff();//
} else {
state = 'rejected';
rjc();
}
});
console.log(state);//check the state somewhere else in the code
of course, this means you must have access to the original code of the promise. If you don't, then you can do:
var state = 'pending';
//you can't access somePromise's code
somePromise.then(function(){
state = 'resolved';
}, function() {
state = 'rejected';
})
console.log(state);//check the promise's state somewhere else in the code
My solution is more coding, but I think you probably wouldn't have to do this for every promise you use.
As of Node.js version 8, you can now use the wise-inspection package to synchronously inspect native promises (without any dangerous hacks).
I made a package for this. Unlike most of the other answers here, it doesn't swallow unhandled rejections.
npm install p-state
import timers from 'timers/promises';
import {promiseStateSync} from 'p-state';
const timeoutPromise = timers.setTimeout(100);
console.log(promiseStateSync(timeoutPromise));
//=> 'pending'
await timeoutPromise;
console.log(promiseStateSync(timeoutPromise));
//=> 'fulfilled'
It looks like somehow nobody came up with one of the simplest solution that doesn't require any hacks:
define a variable to indicate that the promise is running
Add a .finally clause to the promise that sets the variable to false (you can do it at any time after the promise is created)
After that in your code just check if the above variable is true or false, to see whether the Promise is still running.
If you want to know not just whether it's finished or not then instead of .finally add a .then and a .catch clauses that set the variable to "resolved" or "rejected".
The only drawback is that the state variable doesn't get set right away (synchronously) when you add the clauses, in case the promise has already finished. Because of this, it's best to add this to the earliest possible place after the creation of the promise.
Example:
async function worker(){
// wait a very short period of time
await (new Promise(resolve => setTimeout(resolve, 100)))
//...
}
const w1=worker()
let w1_running=true
w1.finally( ()=> {w1_running=false});
//...
//Then check if it's running
(async ()=>{
while(true){
if (w1_running) {
console.log("Still Busy :(")
} else {
console.log("All done :)")
break
}
await (new Promise(resolve => setTimeout(resolve, 10)))
}
})()
// Note we need some async action started otherwise the event loop would never reach the code in the function `worker` or in the `.finally` clause
Here is a more fleshed out es6 version of the QueryablePromise, allowing the ability to chain then and catch after the first resolve and to immediately resolve or reject to keep the api consistent with the native Promise.
const PROMISE = Symbol('PROMISE')
const tap = fn => x => (fn(x), x)
const trace = label => tap(x => console.log(label, x))
class QueryablePromise {
resolved = false
rejected = false
fulfilled = false
catchFns = []
constructor(fn) {
this[PROMISE] = new Promise(fn)
.then(tap(() => {
this.fulfilled = true
this.resolved = true
}))
.catch(x => {
this.fulfilled = true
this.rejected = true
return Promise.reject(x)
})
}
then(fn) {
this[PROMISE].then(fn)
return this
}
catch(fn) {
this[PROMISE].catch(fn)
return this
}
static resolve(x) {
return new QueryablePromise((res) => res(x))
}
static reject(x) {
return new QueryablePromise((_, rej) => rej(x))
}
}
const resolvedPromise = new QueryablePromise((res) => {
setTimeout(res, 200, 'resolvedPromise')
})
const rejectedPromise = new QueryablePromise((_, rej) => {
setTimeout(rej, 200, 'rejectedPromise')
})
// ensure our promises have not been fulfilled
console.log('test 1 before: is resolved', resolvedPromise.resolved)
console.log('test 2 before: is rejected', rejectedPromise.rejected)
setTimeout(() => {
// check to see the resolved status of our promise
console.log('test 1 after: is resolved', resolvedPromise.resolved)
console.log('test 2 after: is rejected', rejectedPromise.rejected)
}, 300)
// make sure we can immediately resolve a QueryablePromise
const immediatelyResolvedPromise = QueryablePromise.resolve('immediatelyResolvedPromise')
// ensure we can chain then
.then(trace('test 3 resolved'))
.then(trace('test 3 resolved 2'))
.catch(trace('test 3 rejected'))
// make sure we can immediately reject a QueryablePromise
const immediatelyRejectedPromise = QueryablePromise.reject('immediatelyRejectedPromise')
.then(trace('test 4 resolved'))
.catch(trace('test 4 rejected'))
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>
2019:
The simple way to do that as I know is thenable , super thin wrapper around promise or any async job.
const sleep = (t) => new Promise(res => setTimeout(res,t));
const sleeping = sleep(30);
function track(promise){
let state = 'pending';
promise = promise.finally( _=> state ='fulfilled');
return {
get state(){return state},
then: promise.then.bind(promise), /*thentable*/
finally:promise.finally.bind(promise),
catch:promise.catch.bind(promise),
}
}
promise = track(sleeping);
console.log(promise.state) // pending
promise.then(function(){
console.log(promise.state); // fulfilled
})
You can extend the Promise class to create a new queryable Promise
class.
You can create your own subclass, say QueryablePromise, by inheriting from the natively available Promise class, the instances of which would have a status property available on it that you can use to query the status of the promise objects synchronously. An implementation of it can be seen below or refer this for a better explanation.
class QueryablePromise extends Promise {
constructor (executor) {
super((resolve, reject) => executor(
data => {
resolve(data)
this._status = 'Resolved'
},
err => {
reject(err)
this._status = 'Rejected'
},
))
this._status = 'Pending'
}
get status () {
return this._status
}
}
// Create a promise that resolves after 5 sec
var myQueryablePromise = new QueryablePromise((resolve, reject) => {
setTimeout(() => resolve(), 5000)
})
// Log the status of the above promise every 500ms
setInterval(() => {
console.log(myQueryablePromise.status)
}, 500)
CAVEAT: process.binding('util').getPromiseDetails is undefined on node 16!
Benchmark:
Candidates:
/**
* https://stackoverflow.com/a/47009572/5318303
*/
const isPromisePending1 = (() => { // noinspection JSUnresolvedFunction
const util = process.binding('util') // noinspection JSUnresolvedFunction
return promise => !util.getPromiseDetails(promise)[0]
})()
/**
* https://stackoverflow.com/a/35852666/5318303
*/
const isPromisePending2 = (promise) => util.inspect(promise) === 'Promise { <pending> }'
/**
* https://stackoverflow.com/a/35820220/5318303
*/
const isPromisePending3 = (promise) => {
const t = {}
return Promise.race([promise, t])
.then(v => v === t, () => false)
}
Test promises:
const a = Promise.resolve()
const b = Promise.reject()
const c = new Promise(() => {})
const x = (async () => 1)()
Run benchmark:
const n = 1000000
console.time('isPromisePending1')
for (let i = 0; i < n; i++) {
isPromisePending1(a)
isPromisePending1(b)
isPromisePending1(c)
isPromisePending1(x)
}
console.timeEnd('isPromisePending1')
console.time('isPromisePending2')
for (let i = 0; i < n; i++) {
isPromisePending2(a)
isPromisePending2(b)
isPromisePending2(c)
isPromisePending2(x)
}
console.timeEnd('isPromisePending2')
console.time('isPromisePending3')
for (let i = 0; i < n; i++) {
await isPromisePending3(a)
await isPromisePending3(b)
await isPromisePending3(c)
await isPromisePending3(x)
}
console.timeEnd('isPromisePending3')
Result:
isPromisePending1: 440.694ms
isPromisePending2: 3.354s
isPromisePending3: 4.761s
Obviously isPromisePending1() is too faster (8~10 times)! But it's not usable on node 16! (see above caveat).
If you're using ES7 experimental you can use async to easily wrap the promise you want to listen.
async function getClient() {
let client, resolved = false;
try {
client = await new Promise((resolve, reject) => {
let client = new Client();
let timer = setTimeout(() => {
reject(new Error(`timeout`, 1000));
client.close();
});
client.on('ready', () => {
if(!resolved) {
clearTimeout(timer);
resolve(client);
}
});
client.on('error', (error) => {
if(!resolved) {
clearTimeout(timer);
reject(error);
}
});
client.on('close', (hadError) => {
if(!resolved && !hadError) {
clearTimeout(timer);
reject(new Error("close"));
}
});
});
resolved = true;
} catch(error) {
resolved = true;
throw error;
}
return client;
}
I've written a little npm package, promise-value, which provides a promise wrapper with a resolved flag:
https://www.npmjs.com/package/promise-value
It also gives synchronous access to the promise value (or error). This doesn't alter the Promise object itself, following the wrap rather than extend pattern.
This is older question but I was trying to do something similar. I need to keep n workers going. They are structured in a promise. I need to scan and see if they are resolved, rejected or still pending. If resolved, I need the value, if rejected do something to correct the issue or pending. If resolved or rejected I need to start another task to keep n going. I can't figure a way to do it with Promise.all or Promise.race as I keep working promises in an array and can find no way to delete them. So I create a worker that does the trick
I need a promise generator function that returns a promise which resolves or rejects as necessary. It is called by a function that sets up the framework to know what the promise is doing.
In the code below the generator simply returns a promise based on setTimeout.
Here it is
//argObj should be of form
// {succeed: <true or false, nTimer: <desired time out>}
function promiseGenerator(argsObj) {
let succeed = argsObj.succeed;
let nTimer = argsObj.nTimer;
return new Promise((resolve, reject) => {
setTimeout(() => {
if (succeed) {
resolve('ok');
}
else {
reject(`fail`);
}
}, nTimer);
})
}
function doWork(generatorargs) {
let sp = { state: `pending`, value: ``, promise: "" };
let p1 = promiseGenerator(generatorargs)
.then((value) => {
sp.state = "resolved";
sp.value = value;
})
.catch((err) => {
sp.state = "rejected";
sp.value = err;
})
sp.promise = p1;
return sp;
}
doWork returns an object containing the promise and the its state and returned value.
The following code runs a loop that tests the state and creates new workers to keep it at 3 running workers.
let promiseArray = [];
promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
promiseArray.push(doWork({ succeed: true, nTimer: 500 }));
promiseArray.push(doWork({ succeed: false, nTimer: 3000 }));
function loopTimerPromise(delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, delay)
})
}
async function looper() {
let nPromises = 3; //just for breaking loop
let nloop = 0; //just for breaking loop
let i;
//let continueLoop = true;
while (true) {
await loopTimerPromise(900); //execute loop every 900ms
nloop++;
//console.log(`promiseArray.length = ${promiseArray.length}`);
for (i = promiseArray.length; i--; i > -1) {
console.log(`index ${i} state: ${promiseArray[i].state}`);
switch (promiseArray[i].state) {
case "pending":
break;
case "resolved":
nPromises++;
promiseArray.splice(i, 1);
promiseArray.push(doWork({ succeed: true, nTimer: 1000 }));
break;
case "rejected":
//take recovery action
nPromises++;
promiseArray.splice(i, 1);
promiseArray.push(doWork({ succeed: false, nTimer: 500 }));
break;
default:
console.log(`error bad state in i=${i} state:${promiseArray[i].state} `)
break;
}
}
console.log(``);
if (nloop > 10 || nPromises > 10) {
//should do a Promise.all on remaining promises to clean them up but not for test
break;
}
}
}
looper();
Tested in node.js
BTW Not in this answer so much but in others on similar topics, I HATE it when someone says "you don't understand" or "that's not how it works" I generally assume the questioner knows what they want. Suggesting a better way is great. A patient explanation of how promises work would also be good.
Old question with many answers but none seem to suggest what I think is the simplest solution: set a bool indicator on promise resolution/rejection.
class Promise2 {
constructor(...args) {
let promise = new Promise(...args);
promise.then(() => promise._resolved_ = true);
promise.catch(() => promise._rejected_ = true);
return promise;
}
}
let p = new Promise2(r => setTimeout(r, 3000));
setInterval(() => {
console.log('checking synchronously if p is resolved yet?', p._resolved_);
}, 1000);
This is the Future pattern I use: (https://github.com/Smallscript-Corp)
enables sync and async fn usage
enables event patterns to be unified with async behavior
class XPromise extends Promise {
state = 'pending'
get settled() {return(this.state !== 'pending')}
resolve(v,...a) {
this.state = 'resolved'
return(this.resolve_(this.value = v,...a))
}
reject(e,...a) {
this.state = 'rejected'
return(this.reject_(this.value = (e instanceof Error) ? e : XPromise.Error(e),...a))
}
static Error(e) {const v = Error('value-rejected'); v.value = e; return(v)}
static Future(fn,...args) { // FactoryFn
let r,t,fv = new XPromise((r_,t_) => {r=r_;t=t_})
fv.resolve_ = r; fv.reject_ = t;
switch(typeof fn) {
case 'undefined': break; case 'function': fn(fv,...args); break;
default: fv.resolve(fn)
}
return(fv)
}
}
global.Future = XPromise.Future
Then you can create future-value instances that can be resolved using sync and async functions; enables handling events uniformly.
You can use it to write a pattern like:
async doSomething() {
// Start both - logically async-parallel
const fvIsNetworkOnLine = this.fvIsNetworkOnline
const fvAuthToken = this.fvAuthToken
// await both (order not critical since both started/queued above)
await fvAuthToken
await fvIsNetworkOnLine
// ... we can check the future values here if needed `fv.resolved`, `fv.state` etc
// ... do dependent workflow here ...
}
onNetworkOnLine(fIsOnline) {
// We utilize the `fv.settled` below, and use the event to `settle` it etc
if(fIsOnline) {
if(this.fvNetworkAvailable_)
this.fvNetworkAvailable_.resolve(true)
this.fvNetworkAvailable_ = undefined
}
else if(this.fvNetworkAvailable_.settled) {
this.fvNetworkAvailable_ = undefined
}
}
get fvNetworkAvailable() {
if(navigator.onLine)
return true
else if(this.fvNetworkAvailable_)
return this.fvNetworkAvailable_
return (this.fvNetworkAvailable_ = Future())
}
get fvAuthToken() {
if(this.fvAuthToken_)
return this.fvAuthToken_
const authTokenFv = async fv => {
// ... handle retry logic etc here ...
}
return(this.fvAuthToken_ = Future(authTokenFv))
}
I found this solution to be simple and allow me to continue using native promises but add useful synchronous checks. I also didn't have to pull in an entire promise library.
CAVEAT: This only works if there is some sort of break in the current execution thread to allow the promises to execute BEFORE checking the synchronous constructs. That makes this of more limited usefulness than I'd initially thought -- still useful for my use case though (Thanks Benjamin Gruenbaum for pointing this out)
/**
* This function allow you to modify a JS Promise by adding some status properties.
* Based on: http://stackoverflow.com/questions/21485545/is-there-a-way-to-tell-if-an-es6-promise-is-fulfilled-rejected-resolved
* But modified according to the specs of promises : https://promisesaplus.com/
*/
function MakeQuerablePromise(promise) {
// Don't modify any promise that has been already modified.
if (promise.isFulfilled) return promise;
// Set initial state
var isPending = true;
var isRejected = false;
var isFulfilled = false;
// Observe the promise, saving the fulfillment in a closure scope.
var result = promise.then(
function(v) {
isFulfilled = true;
isPending = false;
return v;
},
function(e) {
isRejected = true;
isPending = false;
throw e;
}
);
result.isFulfilled = function() { return isFulfilled; };
result.isPending = function() { return isPending; };
result.isRejected = function() { return isRejected; };
return result;
}
wrappedPromise = MakeQueryablePromise(Promise.resolve(3));
setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);
From https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved which based their answer on Is there a way to tell if an ES6 promise is fulfilled/rejected/resolved?

Categories

Resources