JavaScript and Promise.all() - javascript

I'm trying to load a bunch of resources async using promises with Jimp.js. The loading code is a disaster trying to chain it all, and I need a cleaner solution.
What I came up with was below. This obviously doesn't do anything, because it's junk code, but I need to know if there was a failure loading any of the resources, and I need to know when they completed.
function doSomething(asdf) {
return new Promise((resolve, reject) => {
//console.log("It is done.");
// Succeed half of the time.
var x = Math.random();
if (x > .5) {
resolve(["SUCCESS",asdf,x])
} else {
reject(["Failure",asdf,x])
}
});
}
func();
function func() {
//Imagine a is actually an image loaded by doSomething
var a=null; doSomething("1").then(function (data) {a = data;},
(err) => {throw new err;});
//Imagine b is a font resource.
var b=null; doSomething("2").then(function (data) {b = data;},
(err) => {throw new err;});
Promise.all([a, b]).then(function() {
console.log(a);
console.log(b);
//Then here I expect everything to be correct, and continue on with the next function.
},
(err) => {console.log('Oops:' + err);}).
catch( (err) => {console.log('Oops:' + err);});
}
For some reason, this never outputs "Oops".
Here is a fail output:
[ 'SUCCESS', '1', 0.756461151774289 ]
null
What am I missing here?
Update
I took part of an answer I received and changed it so that it behaves exactly as I wanted:
function func() {
var a=doSomething("1").then(function (data) {a = data;});
var b=doSomething("2").then(function (data) {b = data;});
Promise.all([a, b]).then(function() {
console.log(a);
console.log(b);
},
(err) => {console.log('Reject:' + err);});
}
Update
Here is the actual code I'm using that's working great now:
LoadResources() {
var ps = [];
console.log("Loading now");
ps.push(jimp.read(this.ipath+"c4box.png").then(function (image) {obj.imBox = image;}));
ps.push(jimp.read(this.ipath+"red.png").then(function (image) {obj.imRed = image;}));
ps.push(jimp.read(this.ipath+"green.png").then(function (image) {obj.imGreen = image;}));
ps.push(jimp.read(this.ipath+"top.png").then(function (image) {obj.imTop = image;}));
ps.push(jimp.read(this.ipath+"bot.png").then(function (image) {obj.imBot = image;}));
ps.push(jimp.loadFont(jimp.FONT_SANS_32_WHITE).then(function (font) {obj.imFont = font;}));
Promise.all(ps).then( () => {
obj.loaded = true;
obj.imBg = new jimp(512, 576, function (err, image) { });
console.log("Actually loaded now.");
obj.StartGame();
});
console.log("Loading commands complete");
}

You cannot use those a and b variables for the images. (See here for the values that would be passed into Promise.all). You need to use variables for the promise objects that doSomething() returns. The images will only be available inside the then callback - Promise.all creates a promise that fulfills with an array of the results:
function func() {
// aPromise is a promise for an image loaded by doSomething
var aPromise = doSomething("1");
// bPromise is a promise for a font resource.
var bPromise = doSomething("2");
Promise.all([aPromise, bPromise]).then(function([a, b]) {
// ^^^^^^
console.log(a);
console.log(b);
// Then here I expect everything to be correct, and continue on with the next function.
}, (err) => {
console.log('Oops:' + err);})
});
}

Promise.all([a, b])
Cause a and b are null as you set them to null. Therefore Promise.all won't wait at all, it will resolve one tick afterwards, and as a and b get resolved / rejected very fast, that might has happened before and a / b gets set before it reaches
console.log(a)
which will log the right results sometimes, but thats based on chance.

Promise.all returns a promise and this promise contains the result of the previous promises
Promise.all([ doSomething('1'), doSomething('2')])
.then(results => {
// results is an array which contains the result of the previous promises
const [a, b] = results
}).catch(err => console.log('Oops:' + err))

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);

Handle promise resolves indvidually in promise.all()

There is a lot of information on how to handle errors when using promise.all() using catch but what I'm trying to achieve is to handle every time a promise inside of this promise.all() resolves. The reason I'm trying to do this is because I am attempting to setup a custom progress bar in console and I need to call the tick method every time a promise is resolved.
this.getNewSources = function () {
var bar = new ProgressBar(':bar', {total: this.getSourceMap().size});
var timer = setInterval(function () {
bar.tick();
if (bar.complete) {
console.log('\ncomplete\n');
clearInterval(timer);
}
}, 100);
let promiseArr = [];
for (let x of this.getSourceMap().values()) {
promiseArr.push(this.requestArticles(x.getName(), x.getCat(), x.getKey()));
}
return Promise.all(promiseArr).then(() => {
console.log("Articles loaded this round: " + this.articles.size);
console.log('all sources updated');
this.loadedArticles = true;
console.log(this.articleCount);
console.log(this.articles.size);
}).catch(e => {
console.log(e);
});
};
I'm trying to figure out a way of being able to call the bar.tick() method when each individual promise resolves.
(Answering my own question.)
I handled it by adding a then handler where I'm getting the promise from requestArticles (where I'm pushing them into the promiseArr array). I had to be sure to pass the value that handler receives out of the handler so it propagates to Promise.all, see *** lines:
this.getNewSources = function () {
var bar = new ProgressBar(':bar', {total: this.getSourceMap().size});
var timer = setInterval(function () {
if (bar.complete) {
console.log('\ncomplete\n');
clearInterval(timer);
}
}, 100);
function updateProgressBar() {
bar.tick()
}
let promiseArr = [];
for (let x of this.getSourceMap().values()) {
promiseArr.push(this.requestArticles(x.getName(), x.getCat(), x.getKey())
.then(value => { // ***
updateProgressBar(); // ***
return value; // ***
}) // ***
);
}
return Promise.all(promiseArr).then(() => {
console.log("Articles loaded this round: " + this.articles.size);
console.log('all sources updated');
this.loadedArticles = true;
console.log(this.articleCount);
console.log(this.articles.size);
}).catch(e => {
console.log(e);
});
};
That way, my handlers get called as the promises complete individually, and since I'm returning the value I receive, the promise created by my call to then will resolve with that value, which Promise.all will see. Rejections will skip over that handler and go straight to the handlers hooked up by Promise.all.
The ascii progress library on npm
Result output in console:
(With thanks to T.J. Crowder for his initial explanation, which made me realize I could do this where I'm pushing onto the array. He said he preferred deleting that answer and having me post this instead.)

JavaScript checking if resource is reachable with fetch

I'm basically just trying to verify if a resource is reachable from the executing client. I can not use XHR, because the target resource doesn't allow that.
I'm pretty new to JS and am currently working with this ( executable here ):
var done = false;
var i = 1;
var t = "https://i.stack.imgur.com/Ya15i.jpg";
while(!done && i < 4)
{
console.log("try "+i);
done = chk(t);
sleep(1000);
i = i+1;
if (done)
{
console.log("Reachable!");
break;
}
else
{
console.log("Unreachable.");
}
}
function chk(target)
{
console.log("checking "+target)
fetch(target, {mode: 'no-cors'}).then(r=>{
return true;
})
.catch(e=>{
return false;
});
}
// busy fake sleep
function sleep(s)
{
var now = new Date().getTime();
while(new Date().getTime() < now + s){ /* busy sleep */ }
}
I was expecting this code to check for the resource, print the result, then wait for a sec. Repeat this until 3 tries were unsuccessful or one of them was successful.
Instead the execution blocks for a while, then prints all of the console.logs at once and the resource is never reachable (which it is).
I do know that the fetch operation is asynchronous, but I figured if I previously declare done and implement a sleep it should work. In the worst case, the while loop would use the previously declared done.
How do I achieve the described behavior? Any advice is welcome.
Your sleep function is blocking, what you really want is a recursive function that returns a promise after checking the url n times with a delay of y seconds etc.
Something like this
function chk(target, times, delay) {
return new Promise((res, rej) => { // return a promise
(function rec(i) { // recursive IIFE
fetch(target, {mode: 'no-cors'}).then((r) => { // fetch the resourse
res(r); // resolve promise if success
}).catch( err => {
if (times === 0) // if number of tries reached
return rej(err); // don't try again
setTimeout(() => rec(--times), delay ) // otherwise, wait and try
}); // again until no more tries
})(times);
});
}
To be used like this
var t = "https://i.stack.imgur.com/Ya15i.jpg";
chk(t, 3, 1000).then( image => {
console.log('success')
}).catch( err => {
console.log('error')
});
And note that this does not fail on 404 or 500, any response is a successful request.
The main problem is that you are trying to return from callback. That makes no sense.
But fetch is Promise based request you can use Promise to simulate delays as well
Something like this should do the trick
// promise based delay
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout))
// check if target can be fetched
const check = target => fetch(target, {...})
.then(response => response.ok)
const ping = (target, times = 3, timeout = 1000) => check(target)
.then(found => {
if(!found && times) { // still can check
// wait then ping one more time
return delay(timeout).then(() => ping(target, times - 1, timeout))
}
return found
})
ping('https://i.stack.imgur.com/Ya15i.jpg')
.then(found => {
console.log(found ? 'Reachable': 'Unreachable')
})
Your chk function returns undefined, you return true/false from promise callbacks not from container function.
You should use recursion and timeout in catch callback.
It will be something like this:
var i = 0;
var done = false;
var t = "https://i.stack.imgur.com/Ya15i.jpg";
(function chk(target){
console.log("checking "+target)
fetch(target, {mode: 'no-cors'}).then(r=>{
done = true;
console.log("Reachable!");
})
.catch(e=>{
console.log("Unreachable.");
if(i<4){
setTimeout(function(){
chk(target)
},1000)
}
});
})(t)
You can't return within a callback. When you do, it is the callback that is returning, not the parent function. If fact, the function chk is never returning anything.
What it sounds like you are intending to do is return the promise returned by fetch. And attempt to fetch three times.
Try this:
const numberOfTries =3;
currentTry = 1;
var t = "https://i.stack.imgur.com/Ya15i.jpg";
chk(t);
function tryCheck(resource, currentTry) {
chk(resource).done(function(){
console.log("Reachable!");
}).catch(function(e) {
console.log("Unreachable.");
if (currentTry >= numberOfTries) return;
sleep(1000);
tryCheck(resource, currentTry + 1);
});
}
function chk(resource) {
console.log("checking "+target);
return fetch(target, {mode: 'no-cors'});
}
Try this, Hope it works
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'no-cors',
cache: 'default' };
var myRequest = new Request('https://i.stack.imgur.com/Ya15i.jpg');
fetch(myRequest,myInit).then(function(response) {
...
});

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?

node.js looping through GETs with promise

I'm new to promises and I'm sure there's an answer/pattern out there but I just couldn't find one that was obvious enough to me to be the right one. I'm using node.js v4.2.4 and https://www.promisejs.org/
This should be pretty easy I think...I need to do multiple blocks of async in a specific order, and one of the middle blocks will be looping through an array of HTTP GETs.
//New Promise = asyncblock1 - FTP List, resolve the returned list array
//.then(asynchblock2(list)) - loop through list array and HTTP GET needed files
//.then(asynchblock3(list)) - update local log
I tried creating a new Promise, resolving it, passing the list to the .then, doing the GET loop, then the file update. I tried using a nested promise.all inside asynchblock2, but it's actually going in reverse order, 3, 2, and 1 due to the timing of those events. Thanks for any help.
EDIT: Ok, this is the pattern that I'm using which works, I just need a GET loop in the middle one now.
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2 sec');
resolve(1);
},
2000);
}).then(() => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('1.5 sec');
// instead of this section, here I'd like to do something like:
// for(var i = 0; i < dynamicarray.length; i++){
// globalvar[i] = ftpclient.getfile(dynamicarray[i])
// }
// after this loop is done, resolve
resolve(1);
},
1500);
});
}).then(() => {
return new Promise((resolve) => {
setTimeout(() => {
console.log('1 sec');
resolve(1);
},
1000);
});
});
EDIT Here is the almost working code!
var pORecAlert = (function(){
var pa;
var newans = [];
var anstodownload = [];
var anfound = false;//anfound in log file
var nexttab;
var lastchar;
var po;
var fnar = [];
var antext = '';
//-->> This section works fine; it's just creating a JSON object from a local file
try{
console.log('trying');
porfile = fs.readFileSync('an_record_files.json', 'utf8');
if(porfile == null || porfile == ''){
console.log('No data in log file - uploaded_files_data.json being initialized!');
plogObj = [];
}
else{
plogObj = JSON.parse(porfile);
}
}
catch(jpfp){
console.log('Error parsing log file for PO Receiving Alert: ' + jpfp);
return endPORecAlertProgram();
};
if((typeof plogObj) === 'object'){
console.log('an_record_files.json log file found and parsed for PO Receiving Alert!');
}
else{
return mkError(ferror, 'pORecAlert');
};
//finish creating JSON Object
pa = new Client();
pa.connect(ftpoptions);
console.log('FTP Connection for FTP Check Acknowledgement begun...');
pa.on('greeting', function(msg){
console.log('FTP Received Greeting from Server for ftpCheckAcknowledgement: ' + msg);
});
pa.on('ready', function(){
console.log('on ready');
//START PROMISE LIST
var listpromise = new Promise((reslp, rejlp) => {
pa.list('/public_html/test/out', false, (cerr, clist) => {
if(cerr){
return mkError(ferror, 'pORecAlert');
}
else{
console.log('Resolving clist');
reslp(clist);
}
});
});
listpromise.then((reclist) => {
ftpplist:
for(var pcl = 0; pcl < reclist.length; pcl++){
console.log('reclist iteration: ' + pcl);
console.log('checking name: ', reclist[pcl].name);
if(reclist[pcl].name.substring(0, 2) !== 'AN'){
console.log('Not AN - skipping');
continue ftpplist;
}
else{//found an AN
for(var plc = 0; plc < plogObj.length; plc++){
if(reclist[pcl].name === plogObj[plc].anname){
//console.log('Found reclist[pcl].name in local log');
anfound = true;
};
};
if(anfound === false){
console.log('Found AN file to download: ', reclist[pcl].name);
anstodownload.push(reclist[pcl].name);
};
};
};
console.log('anstodownload array:');
console.dir(anstodownload);
return anstodownload;
}).then((fnar) => {
//for simplicity/transparency, here is the array being overwritten
fnar = new Array('AN_17650_37411.699.txt', 'AN_17650_37411.700', 'AN_17650_37411.701', 'AN_17650_37411.702.txt', 'AN_17650_37411.801', 'AN_17650_37411.802.txt');
return Promise.all(fnar.map((gfname) => {
var nsalertnames = [];
console.log('Getting: ', gfname);
debugger;
pa.get(('/public_html/test/out/' + gfname), function(err, anstream){//THE PROBLEM IS THAT THIS GET GETS TRIGGERED AN EXTRA TIME FOR EVERY OTHER FILE!!!
antext = '';
console.log('Get begun for: ', gfname);
debugger;
if(err){
ferror.nsrest_trace = 'Error - could not download new AN file!';
ferror.details = err;
console.log('Error - could not download new AN file!');
console.log('************************* Exiting *************************')
logError(ferror, gfname);
}
else{
// anstream.on('data', (anchunk) => {
// console.log('Receiving data for: ', gfname);
// antext += anchunk;
// });
// anstream.on('end', () => {
// console.log('GET end for: ', gfname);
// //console.log('path to update - gfname ', gfname, '|| end text.');
// fs.appendFileSync(path.resolve('test/from', gfname), antext);
// console.log('Appended file');
// return antext;
// });//end end
};
});//get end
}));//end Promise.all and map
}).then((res99) => {
// pa.end();
// return Promise(() => {
console.log('end all. res99: ', res99);
// //res4(1);
// return 1;
// });
});
});
})();
-->> What happens here:
So I added the almost working code. What is happening is that for every other file, an additional Get request gets made (I don't know how it's being triggered), which fails with an "Unable to make data connection".
So for my iteration over this array of 6, there ends up being 9 Get requests. Element 1 gets requested (works and expected), then 2 (works and expected), then 2 again (fails and unexpected/don't know why it was triggered). Then 3 (works and expected), then 4 (works and expected), then 4 again (fails and unexpected) etc
what you need is Promise.all(), sample code for your app:
...
}).then(() => {
return Promise.all(arry.map(item => ftpclient.getFile(item)))
}).then((resultArray) => {
...
So thanks for the help (and the negative votes with no useful direction!)
I actually reached out to a good nodejs programmer and he said that there seemed to be a bug in the ftp module I was using, and even when trying to use a blackbird .map, the quick succession of requests somehow kicked off an error. I ended up using promise-ftp, blackbird, and promiseTaksQueue - the kicker was that I needed interval. Without it the ftp would end up causing a strange illogical error in the ftp module.
You need the async library. Use the async.eachSeries in situations where you need to use asynchronous operations within a loop, then execute a function when all of those are complete. There are many variations depending on the flow you want but this library does it all.
https://github.com/caolan/async
async.each(theArrayToLoop, function(item, callback) {
// Perform async operation on item here.
doSomethingAsync(item).then(function(){
callback();
})
}, function(err){
//All your async calls are finished continue along here
});

Categories

Resources