Is the resolve function necessary for promise constructor? - javascript

Consider the following promise array
const promiseArray = [1, 2, 3].map(num =>
new Promise(async resolve => {
while (num > 0) {
await foo();
num--;
}
await bar(num);
resolve(); // No value to return
})
);
const a = Promise.all(promiseArray);
Is the resolve function necessary?
Can we omit it and turn the promise into something like this?
const promiseArray = [1, 2, 3].map(num =>
new Promise(async () => {
while (num > 0) {
await foo();
num--;
}
await bar(num);
})
);
const a = Promise.all(promiseArray);

Yes, calling resolve or reject is necessary when using the new Promise constructor, otherwise the promise will stay pending.
However, in your case, you shouldn't be using new Promise at all:
const promiseArray = [1, 2, 3].map(async num => {
while (num > 0) {
await foo();
num--;
}
await bar(num);
});
const a = Promise.all(promiseArray);

Can we omit it and turn the promise into something like this?
No, you cannot. Without calling resolve(), your new Promise() will never resolve. When you then call:
const a = Promise.all(promiseArray);
None of the promises in promiseArray will ever resolve. So, the promise a will never resolve. So, none of this will be of any use and you will have no way of knowing when everything is done executing.
It doesn't appear you really need to wrap anything in a promise here. You can just do this:
async function runLoop() {
for (let i = 1; i <= 3; i++) {
let num = i;
while (num > 0) {
await foo();
num--;
}
await bar(num); // note this will always be bar(0)
}
}
runLoop().then(() => {
console.log("all done");
}).catch(err => {
console.log(err);
});
Or, if you want your separate loops to run in parallel, you can do this:
const promiseArray = [1, 2, 3].map(async num => {
while (num > 0) {
await foo();
num--;
}
await bar(num); // note this will always be bar(0)
});
Promise.all(promiseArray).then(() => {
console.log("all done");
}).catch(err => {
console.log(err);
});

When you create the promise using constructor, first parameter should be called to resolve the promise, the second parameter(if present) to the function should be called to reject the promise. If you are not calling any of the params then promise will be in the pending state always. More information
I think you are confused with async/await and promises.
When you specify async function it will always return resolved promise unless you throw an error inside function which is not caught.
For example:
async function hello(){ return 1}
hello().then((val) => console.log(val));
The same example you can implement using promises
let promise = return new Promise((resolve) => return resolve(1));
promise.then((val) => console.log(val));

Related

Node.js I keep getting Promise { <pending> } when I make an API call then try to save results to variable and then log to console [duplicate]

I read that async functions marked by the async keyword implicitly return a promise:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
but that is not coherent...assuming doSomethingAsync() returns a promise, and the await keyword will return the value from the promise, not the promise itsef, then my getVal function should return that value, not an implicit promise.
So what exactly is the case? Do functions marked by the async keyword implicitly return promises or do we control what they return?
Perhaps if we don't explicitly return something, then they implicitly return a promise...?
To be more clear, there is a difference between the above and
function doSomethingAync(charlie) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(charlie || 'yikes');
}, 100);
})
}
async function getVal(){
var val = await doSomethingAync(); // val is not a promise
console.log(val); // logs 'yikes' or whatever
return val; // but this returns a promise
}
var ret = getVal();
console.log(ret); //logs a promise
In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an async function, it will force wrap it in a promise.
I don't have a big problem with it, but it does defy normal JS.
The return value will always be a promise. If you don't explicitly return a promise, the value you return will automatically be wrapped in a promise.
async function increment(num) {
return num + 1;
}
// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));
Same thing even if there's no return! (Promise { undefined } is returned)
async function increment(num) {}
Same thing even if there's an await.
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function incrementTwice(num) {
const numPlus1 = await defer(() => num + 1);
return numPlus1 + 1;
}
// Logs: 5
incrementTwice(3).then(num => console.log(num));
Promises auto-unwrap, so if you do return a promise for a value from within an async function, you will receive a promise for the value (not a promise for a promise for the value).
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function increment(num) {
// It doesn't matter whether you put an `await` here.
return defer(() => num + 1);
}
// Logs: 4
increment(3).then(num => console.log(num));
In my synopsis the behavior is indeed inconsistent with traditional
return statements. It appears that when you explicitly return a
non-promise value from an async function, it will force wrap it in a
promise. I don't have a big problem with it, but it does defy normal
JS.
ES6 has functions which don't return exactly the same value as the return. These functions are called generators.
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);
Yes, an async function will always return a promise.
According to the tc39 spec, an async function desugars to a generator which yields Promises.
Specifically:
async function <name>?<argumentlist><body>
Desugars to:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
Where spawn "is a call to the following algorithm":
function spawn(genF, self) {
return new Promise(function(resolve, reject) {
var gen = genF.call(self);
function step(nextF) {
var next;
try {
next = nextF();
} catch(e) {
// finished with failure, reject the promise
reject(e);
return;
}
if(next.done) {
// finished with success, resolve the promise
resolve(next.value);
return;
}
// not finished, chain off the yielded promise and `step` again
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
Your question is: If I create an async function should it return a promise or not? Answer: just do whatever you want and Javascript will fix it for you.
Suppose doSomethingAsync is a function that returns a promise. Then
async function getVal(){
return await doSomethingAsync();
}
is exactly the same as
async function getVal(){
return doSomethingAsync();
}
You probably are thinking "WTF, how can these be the same?" and you are right. The async will magically wrap a value with a Promise if necessary.
Even stranger, the doSomethingAsync can be written to sometimes return a promise and sometimes NOT return a promise. Still both functions are exactly the same, because the await is also magic. It will unwrap a Promise if necessary but it will have no effect on things that are not Promises.
Just add await before your function when you call it :
var ret = await getVal();
console.log(ret);
async doesn't return the promise, the await keyword awaits the resolution of the promise. async is an enhanced generator function and await works a bit like yield
I think the syntax (I am not 100% sure) is
async function* getVal() {...}
ES2016 generator functions work a bit like this. I have made a database handler based in top of tedious which you program like this
db.exec(function*(connection) {
if (params.passwd1 === '') {
let sql = 'UPDATE People SET UserName = #username WHERE ClinicianID = #clinicianid';
let request = connection.request(sql);
request.addParameter('username',db.TYPES.VarChar,params.username);
request.addParameter('clinicianid',db.TYPES.Int,uid);
yield connection.execSql();
} else {
if (!/^\S{4,}$/.test(params.passwd1)) {
response.end(JSON.stringify(
{status: false, passwd1: false,passwd2: true}
));
return;
}
let request = connection.request('SetPassword');
request.addParameter('userID',db.TYPES.Int,uid);
request.addParameter('username',db.TYPES.NVarChar,params.username);
request.addParameter('password',db.TYPES.VarChar,params.passwd1);
yield connection.callProcedure();
}
response.end(JSON.stringify({status: true}));
}).catch(err => {
logger('database',err.message);
response.end(JSON.stringify({status: false,passwd1: false,passwd2: false}));
});
Notice how I just program it like normal synchronous particularly at
yield connection.execSql and at yield connection.callProcedure
The db.exec function is a fairly typical Promise based generator
exec(generator) {
var self = this;
var it;
return new Promise((accept,reject) => {
var myConnection;
var onResult = lastPromiseResult => {
var obj = it.next(lastPromiseResult);
if (!obj.done) {
obj.value.then(onResult,reject);
} else {
if (myConnection) {
myConnection.release();
}
accept(obj.value);
}
};
self._connection().then(connection => {
myConnection = connection;
it = generator(connection); //This passes it into the generator
onResult(); //starts the generator
}).catch(error => {
reject(error);
});
});
}

Why async returns promise in JS [duplicate]

I read that async functions marked by the async keyword implicitly return a promise:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
but that is not coherent...assuming doSomethingAsync() returns a promise, and the await keyword will return the value from the promise, not the promise itsef, then my getVal function should return that value, not an implicit promise.
So what exactly is the case? Do functions marked by the async keyword implicitly return promises or do we control what they return?
Perhaps if we don't explicitly return something, then they implicitly return a promise...?
To be more clear, there is a difference between the above and
function doSomethingAync(charlie) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(charlie || 'yikes');
}, 100);
})
}
async function getVal(){
var val = await doSomethingAync(); // val is not a promise
console.log(val); // logs 'yikes' or whatever
return val; // but this returns a promise
}
var ret = getVal();
console.log(ret); //logs a promise
In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an async function, it will force wrap it in a promise.
I don't have a big problem with it, but it does defy normal JS.
The return value will always be a promise. If you don't explicitly return a promise, the value you return will automatically be wrapped in a promise.
async function increment(num) {
return num + 1;
}
// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));
Same thing even if there's no return! (Promise { undefined } is returned)
async function increment(num) {}
Same thing even if there's an await.
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function incrementTwice(num) {
const numPlus1 = await defer(() => num + 1);
return numPlus1 + 1;
}
// Logs: 5
incrementTwice(3).then(num => console.log(num));
Promises auto-unwrap, so if you do return a promise for a value from within an async function, you will receive a promise for the value (not a promise for a promise for the value).
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function increment(num) {
// It doesn't matter whether you put an `await` here.
return defer(() => num + 1);
}
// Logs: 4
increment(3).then(num => console.log(num));
In my synopsis the behavior is indeed inconsistent with traditional
return statements. It appears that when you explicitly return a
non-promise value from an async function, it will force wrap it in a
promise. I don't have a big problem with it, but it does defy normal
JS.
ES6 has functions which don't return exactly the same value as the return. These functions are called generators.
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);
Yes, an async function will always return a promise.
According to the tc39 spec, an async function desugars to a generator which yields Promises.
Specifically:
async function <name>?<argumentlist><body>
Desugars to:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
Where spawn "is a call to the following algorithm":
function spawn(genF, self) {
return new Promise(function(resolve, reject) {
var gen = genF.call(self);
function step(nextF) {
var next;
try {
next = nextF();
} catch(e) {
// finished with failure, reject the promise
reject(e);
return;
}
if(next.done) {
// finished with success, resolve the promise
resolve(next.value);
return;
}
// not finished, chain off the yielded promise and `step` again
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
Your question is: If I create an async function should it return a promise or not? Answer: just do whatever you want and Javascript will fix it for you.
Suppose doSomethingAsync is a function that returns a promise. Then
async function getVal(){
return await doSomethingAsync();
}
is exactly the same as
async function getVal(){
return doSomethingAsync();
}
You probably are thinking "WTF, how can these be the same?" and you are right. The async will magically wrap a value with a Promise if necessary.
Even stranger, the doSomethingAsync can be written to sometimes return a promise and sometimes NOT return a promise. Still both functions are exactly the same, because the await is also magic. It will unwrap a Promise if necessary but it will have no effect on things that are not Promises.
Just add await before your function when you call it :
var ret = await getVal();
console.log(ret);
async doesn't return the promise, the await keyword awaits the resolution of the promise. async is an enhanced generator function and await works a bit like yield
I think the syntax (I am not 100% sure) is
async function* getVal() {...}
ES2016 generator functions work a bit like this. I have made a database handler based in top of tedious which you program like this
db.exec(function*(connection) {
if (params.passwd1 === '') {
let sql = 'UPDATE People SET UserName = #username WHERE ClinicianID = #clinicianid';
let request = connection.request(sql);
request.addParameter('username',db.TYPES.VarChar,params.username);
request.addParameter('clinicianid',db.TYPES.Int,uid);
yield connection.execSql();
} else {
if (!/^\S{4,}$/.test(params.passwd1)) {
response.end(JSON.stringify(
{status: false, passwd1: false,passwd2: true}
));
return;
}
let request = connection.request('SetPassword');
request.addParameter('userID',db.TYPES.Int,uid);
request.addParameter('username',db.TYPES.NVarChar,params.username);
request.addParameter('password',db.TYPES.VarChar,params.passwd1);
yield connection.callProcedure();
}
response.end(JSON.stringify({status: true}));
}).catch(err => {
logger('database',err.message);
response.end(JSON.stringify({status: false,passwd1: false,passwd2: false}));
});
Notice how I just program it like normal synchronous particularly at
yield connection.execSql and at yield connection.callProcedure
The db.exec function is a fairly typical Promise based generator
exec(generator) {
var self = this;
var it;
return new Promise((accept,reject) => {
var myConnection;
var onResult = lastPromiseResult => {
var obj = it.next(lastPromiseResult);
if (!obj.done) {
obj.value.then(onResult,reject);
} else {
if (myConnection) {
myConnection.release();
}
accept(obj.value);
}
};
self._connection().then(connection => {
myConnection = connection;
it = generator(connection); //This passes it into the generator
onResult(); //starts the generator
}).catch(error => {
reject(error);
});
});
}

JavaScript Promises: Executing Promises Sequentially

In an attempt to understand promises more clearly, i have been reading up a few very interesting articles on the same. I came across the following code which works perfectly for executing promises sequentially. But i am not able to understand how it works.
function doFirstThing(){
return new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(1);
},1000)
})
}
function doSecondThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(res + 1);
},1000)
})
}
function doThirdThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
resolve(res + 2);
},1000)
})
}
promiseFactories = [doFirstThing, doSecondThing, doThirdThing];
function executeSequentially(promiseFactories) {
var result = Promise.resolve(); // this is the most problematic line
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory);// what is happening here ?
});
return result;
}
executeSequentially(promiseFactories)
I do understand that promises are executed as soon as they are created. For some reason i am not able to understand the flow of execution. Especially this following line:
var result = Promise.resolve()//and empty promise is created.
Please if somebody can help me understand how calling the promiseFactory method inside the 'then' method of the empty promise makes it execute sequentially, like so. Or is it because of the forEach loop ?
result = result.then(promiseFactory);
I tried replacing the 'forEach' with a 'map' function and still yielded the same result. i.e, the methods where executed sequentially.
Also, how is the value passed from one chained function to other ?
Any help or article/blog is highly appreciated.
You can image a Promise as a box with execution inside. As far as the promise is created, the execution starts. To get the result value, you have to open the box. You can use then for it:
Promise.resolve(5).then(result => console.log(result)); // prints 5
If you want to chain promises you can do it by opening the box one by one:
Promise.resolve(5)
.then(result => Promise.resolve(result + 1))
.then(result => Promise.resolve(result * 2))
.then(result => console.log(result)); // prints 12
This chaining makes the executions synchronous (one by one).
If you want to execute several promises asynchronously (you don't chain results), you can use Promise.all:
Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)])
.then(result => console.log(result)); // prints [1,2,3]
In your case:
Promise.all(promiseFactories).then(result => console.log(result));
Another option how to work with promises is to await them:
(async ()=> {
var res1 = await Promise.resolve(5);
var res2 = await Promise.resolve(res1 + 1);
var res3 = await Promise.resolve(res2 * 2);
console.log(res3); // prints 12
})();
await works similar to then - it makes asynchronous execution to synchronous.
In your case:
async function executeSequentially(promiseFactories) {
for (const p of promiseFactories) {
const result = await p;
console.log(result);
}
}
Note: await packs a value into a Promise out of the box:
var res1 = await 5; // same as await Promise.resolve(5)
The executeSequentially method returns all the Promises one after each other. It happens to iterate over promiseFactory, but it could be written as:
function executeSequentially(promiseFactories) {
return doFirstThing()
.then(() => doSecondThing())
.then(doThirdThing() );
}
It is just the same. We are basically returning a Promise.
Now, however, we want to iterate over a collection of promises.
When iterating, we need to attach the current Promise to the previous with a then. But the forEach does not expose the next Promise -or the previous- in every iteration. And yet we still need it in order to keep chaining Promises one by one. Hence, the result 'hack':
function executeSequentially(promiseFactories) {
var result = Promise.resolve(); /*We need a thing that keeps yelling
the previous promise in every iteration, so we can keep chaining.
This 'result' var is that thing. This is keeping a Promise in every
iteration that resolves when all the previous promises resolve
sequentially. Since we don't have a Promise in the array
previous to the first one, we fabricate one out of 'thin air'
with Promise.resolve() */
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory); /* Here result is update
with a new Promise, with is the result of chaining `result`
with the current one. Since `result` already had all the previous ones,
at the end, `result` will be a Promise that depends upon all the
Promises resolution.*/
});
return result;
}
Now, there's also a syntax quirk that maybe is puzzling you:
result = result.then(promiseFactory);
This line is pretty much the same as the following:
result = result.then(resolvedValue => promiseFactory(resolvedValue));
Please if somebody can help me understand how calling the promiseFactory method inside the 'then' method of the empty promise makes it execute sequentially, like so. Or is it because of the forEach loop ?
First thing first, promiseFactory is a pretty bad name there. The method should be better written as follows:
function executeSequentially(promises) {
var result = Promise.resolve(); // this is the most problematic line
promises.forEach(function (currentPromise) {
result = result.then(currentPromise);// what is happening here ?
});
return result;
}
So:
how calling the currentPromise method inside the 'then' method of the empty promise makes it execute sequentially?
It makes execute sequentially because when you attach a Promise to another by then, it executes sequentially. Is a then thing, it is not at all related to the fact that we are iterating over Promises. With plain Promises outside an iteration it works pretty much the same:
Promise.resolve() // fake Promises that resolves instanly
.then(fetchUsersFromDatabase) // a function that returns a Promise and takes
// like 1 second. It won't be called until the first one resolves
.then(processUsersData) // another function that takes input from the first, and
// do a lot of complex and asynchronous computations with data from the previous promise.
// it won't be called until `fetchUsersFromDatabase()` resolves, that's what
// `then()` does.
.then(sendDataToClient); // another function that will never be called until
// `processUsersData()` resolves
It is always recommended to use Promise.all if you want such behaviour:
function doFirstThing() {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(1);
}, 1000)
})
}
function doSecondThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 1);
}, 1000)
})
}
function doThirdThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 2);
}, 1000)
})
}
let promiseFactories = [doFirstThing(2), doSecondThing(1), doThirdThing(3)];
Promise.all(promiseFactories)
.then(data => {
console.log("completed all promises", data);
})
To run it sequentially one after another:
function doFirstThing() {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(1);
}, 1000)
})
}
function doSecondThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 1);
}, 3000)
})
}
function doThirdThing(res) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve(res + 2);
}, 5000)
})
}
promiseFactories = [doFirstThing, doSecondThing, doThirdThing];
function executeSequentially(promiseFactories) {
promiseFactories.forEach(function(promiseFactory) {
promiseFactory(1).then((data) => {
console.log(data)
});
});
}
executeSequentially(promiseFactories);
If we lay out the foreach loop it will look like the following
function doFirstThing(){
return new Promise(function(resolve,reject){
setTimeout(()=>{
console.log(1);
resolve(1);
},1000)
})
}
function doSecondThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
console.log(2);
resolve(res + 1);
},2000)
})
}
function doThirdThing(res){
return new Promise(function(resolve,reject){
setTimeout(()=>{
console.log(3);
resolve(res + 2);
},3000)
})
}
Promise.resolve()
.then(doFirstThing())
.then(doSecondThing())
.then(doThirdThing());
I do understand that promises are executed as soon as they are created. For some reason i am not able to understand the flow of execution. Especially this following line:
var result = Promise.resolve()//and empty promise is created.
This is just to get hold of the promise chain's starting point. Here it is an already resolved promise. To better understand it you can use one of your promises to get hold of the promise chain like below.
let promiseFactories= [doSecondThing, doThirdThing];
let result = doFirstThing();
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory);
});
This will also work.

Async/Await error

Can someone help me understand why the following code prints blank? I'm expecting it to print "done" as I assume that the await will make the program wait for the promise to resolve.
Thanks for the help!
var y = '';
async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait till the promise resolves (*)
y = result;
}
f().then(console.log(y));
You must pass a callback function to then, not call console.log immediately and pass its return value:
f().then(() => console.log(y));
Of course the code would be much better if you didn't use a global variable but rather returned the value from the async function so that the promise fulfilled with it:
async function f() {
const promise = new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
});
await promise;
const result = "done!";
return result;
}
f().then((y) => console.log(y));

ES6 promises with timeout interval

I'm trying to convert some of my code to promises, but I can't figure out how to chain a new promise inside a promise.
My promise function should check the content of an array every second or so, and if there is any item inside it should resolve. Otherwise it should wait 1s and check again and so on.
function get(){
return new Promise((resolve) => {
if(c.length > 0){
resolve(c.shift());
}else{
setTimeout(get.bind(this), 1000);
}
});
}
let c = [];
setTimeout(function(){
c.push('test');
}, 2000);
This is how I expect my get() promise function to work, it should print "test" after 2 or 3 seconds max:
get().then((value) => {
console.log(value);
});
Obviously it doesn't work, nothing is ever printed
setTimeout has terrible chaining and error-handling characteristics on its own, so always wrap it:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
function get(c) {
if (c.length) {
return Promise.resolve(c.shift());
}
return wait(1000).then(() => get(c)); // try again
}
let c = [];
get(c).then(val => console.log(val));
wait(2000).then(() => c.push('test'));
While you didn't ask, for the benefit of others, this is a great case where async/await shines:
const wait = ms => new Promise(r => setTimeout(r, ms));
async function get(c) {
while (!c.length) {
await wait(1000);
}
return c.shift();
}
let c = [];
get(c).then(val => console.log(val));
wait(2000).then(() => c.push('test'));
Note how we didn't need Promise.resolve() this time, since async functions do this implicitly.
The problem is that your recursive call doesn't pass the resolve function along, so the else branch can never call resolve.
One way to fix this would be to create a closure inside the promise's callback so that the recursive call will have access to the same resolve variable as the initial call to get.
function get() {
return new Promise((resolve) => {
function loop() {
if (c.length > 0) {
resolve(c.shift());
} else {
setTimeout(loop, 1000);
}
}
loop();
});
}
let c = [];
setTimeout(function() {
c.push('test');
}, 2000);
get().then(val => console.log(val));
In the else case, you never resolve that promise. get might create another one, but it is returned to nowhere.
You should promisify your asynchronous function (setTimeout) on the lowest level, and then only chain your promises. By returning the result of the recursive call from a then callback, the resulting promise will resolve with the same result:
function delayAsync(time) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
function get(c) {
if (c.length > 0){
return Promise.resolve(c.shift());
} else {
return delay(1000).then(() => {
return get(c); // try again
});
}
}
What you need is a polling service, which checks periodically for specific condition prior proceeding with promise resolution. Currently when you run setTimeout(get.bind(this), 1000); you are creating a new instance of the promise without actually resolving the initial promise, because you don't reference to the initial resolve function that you created.
Solution:
Create a new callback function that you can reference to it inside the promise
Pass the resolve & reject as params in the setTimeout invocation e.g. setTimeout(HandlePromise, 1000, resolve, reject, param3, param4 ..); setTimeout API
function get() {
var handlerFunction = resolve => {
if (c.length > 0) {
resolve(c.shift());
} else {
setTimeout(handlerFunction, 1000, resolve);
}
};
return new Promise(handlerFunction);
}
let c = [];
setTimeout(function() {
c.push("test");
}, 2000);
get().then(value => {
console.log(value);
});
For more information look into javascript polling article
You could try this solution. Since JS needs to free itself to download the images, I use await within an asynchronous function and an asynchronous call to wake up JS after a delay
private async onBeforeDoingSomething() : void {
await this.delay(1000);
console.log("All images are loaded");
}
private delay (ms : number = 500) : Promise<number> {
return new Promise((resolve,reject) => {
const t = setTimeout( () => this.areImgsLoaded(resolve), ms);
});
}
private async areImgsLoaded (resolve) {
let reload = false;
const img = document.querySelectorAll('img');
console.log("total of images: ",img.length);
for (let i = 0; i < img.length; i++){
if (!img[i]["complete"]) {
console.log("img not load yet");
reload = true;
break;
}
}
if (reload) {
await this.delay();
}
resolve();
}
Use setInterval to check every second. Run this script to understand.
let c = [];
function get(){
return new Promise((resolve) => {
var i = setInterval(function(){
if(c.length > 0){
resolve(c.shift());
clearInterval(i);
}
}, 1000);
});
}
setTimeout(function(){
c.push('test');
}, 2000);
get().then((value) => {
console.log(value);
});

Categories

Resources