Async function never stops running - javascript

I am running this function with NodeJS, but the process never stops running, despite the fact that I am returning a value once all promises have been resolved.
How can I modify this code so the function terminates when it's done?
let Parser = require('rss-parser');
let parser = new Parser();
var sources = {
feed1: 'http://www.example.url/feed',
feed2: 'http://www.another.url/feed'
}
(async() => {
var promises = [];
for (var feedName in sources) {
if (sources.hasOwnProperty(feedName)) {
const result = parser.parseURL(sources[feedName])
promises.push(result)
}
}
return await Promise.all(promises)
})()

You can take a simple approach handling promises in one array to catch them after parsing each url. Something like this:
let Parser = require('rss-parser');
let parser = new Parser();
var sources = {
feed1: 'http://www.example.url/feed',
feed2: 'http://www.another.url/feed'
}
function parsePromise(url) {
return new Promise((resolve,reject) => {
let data = parser.parseURL(url);
resolve(data);
});
}
// main
toread = [];
for (var feedName in sources) {
let url = sources[feedName];
let p = parsePromise(url);
toread.push(p);
}
Promise.all(toread).then((data) => {
console.log(data);
});

First, I think your async arrow function is incorrect. You are not actually invoking it properly. See the syntax for async arrow functions in this question: Syntax for async arrow function.
Since you are already trying to do an immediate anonymous function, just use the function declaration instead of arrows.
Additionally, you are trying to return something from an anonymous, immediately invoked function and you aren't doing anything with the returned value.
Not only that, but you are awaiting the Promise.all() only to have whatever you waited on get wrapped in a Promise anyway since async functions return Promises no matter what.
Second, use more map()s or intermediate values so you program flows more clearly. The benefit of await is that you can write what looks like synchronous code, but it will be handled in an asynchronous manner.
const Parser = require("rss-parser"),
parser = new Parser();
const sources = {
feed1: "https://sports.yahoo.com/nhl/teams/bos/rss.xml",
feed2: "https://sports.yahoo.com/nhl/teams/buf/rss.xml"
};
(async function () {
let data
try {
const sourcesArr = Object.keys(sources).map(k => sources[k]),
feedPromises = sourcesArr.map(source => parser.parseURL(source));
data = await Promise.all(feedPromises);
} catch (err) {
console.error(err);
}
console.log(data);
}());

Related

NodeJs javascript: wait until the previous object property is assigned before assigning the next property

Suppose I have code like this:
let result = {
name: downloadNameFromInternetVerySlow(),
isFamous: determineIfNameIsFamous(this.name);
}
const downloadNameFromInternetVerySlow = () => {
path = "/home";
const folders = fs.readdirSync(path).filter(file => fs.lstatSync(path).isDirectory());
console.log(folders);
return folders[0];
}
downloadNameFromInternetVerySlow can take a long time, meanwhile determineIfNameIsFamous depends on downloadNameFromInternetVerySlow's result to return correct value.
How do I make sure determineIfNameIsFamous only runs after downloadNameFromInternetVerySlow is done?
The code you show is entirely synchronous so asynchronous results aren't actually the issue here like people were guessing. The issue is that this.name cannot be used to refer to a prior property in an object literal definition for several reasons, not the least of which this isn't set to the object you want.
Instead, you can do this:
let result = {};
result.name = downloadNameFromInternetVerySlow();
result.isFamous = determineIfNameIsFamous(result.name);
You can convert downloadNameFromInternetVerySlow to a Promise(if not already). and then user await to wait till it finished. Otherwise you can use Promise.then()
(This should be inside an async function)
let name = await downloadNameFromInternetVerySlow(),
let isFamous = determineIfNameIsFamous(this.name);
let result = {
name,
isFamous
}
Another method using Promise.then
let name, isFamous;
downloadNameFromInternetVerySlow().then(result => {
name = result;
isFamous = determineIfNameIsFamous(this.name);
});
Async/await
There’s a special syntax to work with promises in a more comfortable fashion, called “async/await”.
An async function returns a promise, like in this example:
const doSomethingAsync = () => {
return new Promise(resolve => {
setTimeout(() => resolve('I did something'), 3000)
})
}
When you want to call this function you prepend await, and the calling code will stop until the promise is resolved or rejected. One caveat: the client function must be defined as async. Here's an example :
const doSomething = async () => {
console.log(await doSomethingAsync())
}
function downloadNameFromInternetVerySlow(){
return new Promise(resolve => setTimeout(() => {
console.log("Set timeout resolving...");
return resolve("Sample Name");
}, 5000))
}
function determineIfNameIsFamous(name){
if(name === "Sample Name"){
return true;
}
return false;
}
async function myFunc(){
let result = {};
result.name = await downloadNameFromInternetVerySlow();
console.log(result);
result.isFamous = determineIfNameIsFamous(result.name);
return result;
}
myFunc().then(res => console.log("result : ", res))
Assuming downloadNameFromInternetVerySlow is asynchrononous (otherwise it would already work like you want), the solution is to use await.
Please note, to be able to do that, this code needs to be wrapped in an async function (or or top level with top level await available.)
async function getAndUseResult(){
let result = {
name: await downloadNameFromInternetVerySlow(),
isFamous: determineIfNameIsFamous(this.name)
}
console.log(JSON.stringify(result))
}
getAndUseResult();

calling an async function inside for loop in JavaScript / node js

I want to call an async function inside for loop
function test(req,res){
//somelogic part here
async function create(data){
//logic part here
}
for( var value in values){
// some codeing part here
await create(data);
}
}
I am getting this error
uncaughtException: await is only valid in async function
then I can't call an async function inside For loop.
I know it is written like this but is there any possible way I can call an async function inside for loop
for await (var value in values)
Just put async in front of function test.
async function test(req, res) {…
If you want to await a promise, then the function that's using await needs to be async function.
Hi As I understood your concern I would suggest to use .map() function which is very useful in this type of case.
async function create(data) {
// Create user logic here
}
const usernames = ['test1', 'test2', 'test3'];
const createdUsers = usernames.map(async (val) => {
const user = await create();
return user;
});
await Promise.all(createdUsers);
Wrap and create new function inside another function isn't a good ideal. You can move function create to outside like the code bellow
async function create(data){
//logic part here
}
async function test(req,res){
//somelogic part here
for( var value in values){
// some codeing part here
await create(data);
}
}
Or use arrow function instead
async function test(req,res){
//somelogic part here
const create = async (data) => {
//logic part here
}
for( var value in values){
// some codeing part here
await create(data);
}
}
If calling just an asynchronous function is only going to part of your for loop mean you can simple push the promise returned by the asynchronous calls to an array and use promise static methods like 'all'
let pros= []
for(){
pro.push(create(data));
}
Promise.all(pros).then(()=> {
#implement rest or resolve another promise
})
Please refer..
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
The problem is not with your create function, but with your test function. The scope where you call the await syntax, needs to be async. Therefore, your scope here is test.
Simply update your code to the following;
/*vv --> async*/
async function test(req, res) {
console.log("test is called");
async function create(to) {
return new Promise((resolve) => {
setTimeout(() => resolve(Date.now()), to);
});
}
const values = {
a: 1e3,
b: 2e3,
c: 3e3
};
for (var value in values) {
// some codeing part here
const to = values[value];
const result = await create(to);
console.log("result:", result);
}
return 1;
}
(async() => {
const res = await test();
console.log("done");
})();
Your question is a little confusing because there doesn't appear to be any reason to async/await - create doesn't appear to return any data so the aync/await seems redundant, and you can probably remove it.
If, however, create does return a value, and you want to wait until all the values have been returned before you continue, create an array of function calls and then use Promise.all to wait until the promises returned from create have resolved.
// `create` returns a promise that resolves
// after two seconds
function create(data){
return new Promise((res, rej) => {
setTimeout(() => res(data), 2000);
});
}
async function test(req,res) {
const values = [1, 2, 3, 4];
// Create an array of promises
const arr = values.map(el => create(el));
// And use Promise.all to wait to resolve them
const output = await Promise.all(arr);
console.log(output);
}
test();
If you put the Promise in the for loop then it will get a total of every responses time in every iteration. So I'm suggesting the Promise.all for that.
async func() {
let arr = [];
for(var value in values){
arr.push(create(data));
}
let createdArr = await Promise.all(arr);
// Using createdArr, you can get all waited responses
}
In here it will get only the most responding time, not the total. All Promises run at the same time.

Using promise in loop results in Promise failure

I'd like to reuse the same code in a loop. This code contains promises. However, when iterating, this code results in an error.
I've tried using for and while loops. There seems to be no issue when I use the for loop for a single iteration.
Here is a minimal version of my code:
var search_url = /* Some initial URL */
var glued = "";
for(var i = 0; i < 2; i++)
{
const prom = request(search_url)
.then(function success(response /* An array from a XMLHTTPRequest*/) {
if (/* Some condition */)
{
search_url = /* Gets next URL */
glued += processQuery(response[0]);
} else {
console.log("Done.")
}
})
.catch(function failure(err) {
console.error(err.message); // TODO: do something w error
})
}
document.getElementById('api-content').textContent = glued;
I expect the results to append to the variable glued but instead, I get an error: failure Promise.catch (async) (anonymous) after the first iteration of the loop.
Answer:
You can use the Symbol.iterator in accordance with for await to perform asynchronous execution of your promises. This can be packaged up into a constructor, in the example case it's called Serial (because we're going through promises one by one, in order)
function Serial(promises = []) {
return {
promises,
resolved: [],
addPromise: function(fn) {
promises.push(fn);
},
resolve: async function(cb = i => i, err = (e) => console.log("trace: Serial.resolve " + e)) {
try {
for await (let p of this[Symbol.iterator]()) {}
return this.resolved.map(cb);
} catch (e) {
err(e);
}
},
[Symbol.iterator]: async function*() {
this.resolved = [];
for (let promise of this.promises) {
let p = await promise().catch(e => console.log("trace: Serial[Symbol.iterator] ::" + e));
this.resolved.push(p);
yield p;
}
}
}
}
What is the above?
It's a constructor called Serial.
It takes as an argument an array of Functions that return Promises.
The functions are stored in Serial.promises
It has an empty array stored in Serial.resolved - this will store the resolved promise requests.
It has two methods:
addPromise: Takes a Function that returns a Promise and adds it to Serial.promises
resolve: Asynchronously calls a custom Symbol.iterator. This iterator goes through every single promise, waits for it to be completed, and adds it to Serial.resolved. Once this is completed, it returns a map function that acts on the populated Serial.resolved array. This allows you to simply call resolve and then provide a callback of what to do with the array of responses. A.e. .resolve()((resolved_requests) => //do something with resolved_requests)
Why does it work?
Although many people don't realize this Symbol.iterator is much more powerful than standard for loops. This is for two big reasons.
The first reason, and the one that is applicable in this situation, is because it allows for asynchronous calls that can affect the state of the applied object.
The second reason is that it can be used to provide two different types of data from the same object. A.e. You may have an array that you would like to read the contents of:
let arr = [1,2,3,4];
You can use a for loop or forEach to get the data:
arr.forEach(v => console.log(v));
// 1, 2, 3, 4
But if you adjust the iterator:
arr[Symbol.iterator] = function* () {
yield* this.map(v => v+1);
};
You get this:
arr.forEach(v => console.log(v));
// 1, 2, 3, 4
for(let v of arr) console.log(v);
// 2, 3, 4, 5
This is useful for many different reasons, including timestamping requests/mapping references, etc. If you'd like to know more please take a look at the ECMAScript Documentation: For in and For Of Statements
Use:
It can be used by calling the constructor with an Array of functions that return Promises. You can also add Function Promises to the Object by using
new Serial([])
.addPromise(() => fetch(url))
It doesn't run the Function Promises until you use the .resolve method.
This means that you can add promises ad hoc if you'd like before you do anything with the asynchronous calls. A.e. These two are the same:
With addPromise:
let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3)]);
promises.addPromise(() => fetch(url4));
promises.resolve().then((responses) => responses)
Without addPromise:
let promises = new Serial([() => fetch(url), () => fetch(url2), () => fetch(url3), () => fetch(url4)])
.resolve().then((responses) => responses)
Data:
Since I can't really replicate your data calls, I opted for JSONPlaceholder (a fake online rest api) to show the promise requests in action.
The data looks like this:
let searchURLs = ["https://jsonplaceholder.typicode.com/todos/1",
"https://jsonplaceholder.typicode.com/todos/2",
"https://jsonplaceholder.typicode.com/todos/3"]
//since our constructor takes functions that return promises, I map over the URLS:
.map(url => () => fetch(url));
To get the responses we can call the above data using our constructor:
let promises = new Serial(searchURLS)
.resolve()
.then((resolved_array) => console.log(resolved_array));
Our resolved_array gives us an array of XHR Response Objects. You can see that here:
function Serial(promises = []) {
return {
promises,
resolved: [],
addPromise: function(fn) {
promises.push(fn);
},
resolve: async function(cb = i => i, err = (e) => console.log("trace: Serial.resolve " + e)) {
try {
for await (let p of this[Symbol.iterator]()) {}
return this.resolved.map(cb);
} catch (e) {
err(e);
}
},
[Symbol.iterator]: async function*() {
this.resolved = [];
for (let promise of this.promises) {
let p = await promise().catch(e => console.log("trace: Serial[Symbol.iterator] ::" + e));
this.resolved.push(p);
yield p;
}
}
}
}
let searchURLs = ["https://jsonplaceholder.typicode.com/todos/1", "https://jsonplaceholder.typicode.com/todos/2", "https://jsonplaceholder.typicode.com/todos/3"].map(url => () => fetch(url));
let promises = new Serial(searchURLs).resolve().then((resolved_array) => console.log(resolved_array));
Getting Results to Screen:
I opted to use a closure function to simply add text to an output HTMLElement.
This is added like this:
HTML:
<output></output>
JS:
let output = ((selector) => (text) => document.querySelector(selector).textContent += text)("output");
Putting it together:
If we use the output snippet along with our Serial object the final functional code looks like this:
let promises = new Serial(searchURLs).resolve()
.then((resolved) => resolved.map(response =>
response.json()
.then(obj => output(obj.title))));
What's happening above is this:
we input all our functions that return promises. new Serial(searchURLS)
we tell it to resolve all the requests .resolve()
after it resolves all the requests, we tell it to take the requests and map the array .then(resolved => resolved.map
the responses we turn to objects by using .json method. This is necessary for JSON, but may not be necessary for you
after this is done, we use .then(obj => to tell it to do something with each computed response
we output the title to the screen using output(obj.title)
Result:
let output = ((selector) => (text) => document.querySelector(selector).textContent += text)("output");
function Serial(promises = []) {
return {
promises,
resolved: [],
addPromise: function(fn) {
promises.push(fn);
},
resolve: async function(cb = i => i, err = (e) => console.log("trace: Serial.resolve " + e)) {
try {
for await (let p of this[Symbol.iterator]()) {}
return this.resolved.map(cb);
} catch (e) {
err(e);
}
},
[Symbol.iterator]: async function*() {
this.resolved = [];
for (let promise of this.promises) {
let p = await promise().catch(e => console.log("trace: Serial[Symbol.iterator] ::" + e));
this.resolved.push(p);
yield p;
}
}
}
}
let searchURLs = ["https://jsonplaceholder.typicode.com/todos/1", "https://jsonplaceholder.typicode.com/todos/2", "https://jsonplaceholder.typicode.com/todos/3"].map(url => () => fetch(url));
let promises = new Serial(searchURLs).resolve()
.then((resolved) => resolved.map(response =>
response.json()
.then(obj => output(obj.title))));
<output></output>
Why go this route?
It's reusable, functional, and if you import the Serial Constructor you can keep your code slim and comprehensible. If this is a cornerstone of your code, it'll be easy to maintain and use.
Using it with your code:
I will add how to specifically use this with your code to fully answer your question and so that you may understand further.
NOTE glued will be populated with the requested data, but it's unnecessary. I left it in because you may have wanted it stored for a reason outside the scope of your question and I don't want to make assumptions.
//setup urls:
var search_urls = ["https://jsonplaceholder.typicode.com/todos/1", "https://jsonplaceholder.typicode.com/todos/2"];
var request = (url) => () => fetch(url);
let my_requests = new Serial(search_urls.map(request));
//setup glued (you don't really need to, but if for some reason you want the info stored...
var glued = "";
//setup helper function to grab title(this is necessary for my specific data)
var addTitle = (req) => req.json().then(obj => (glued += obj.title, document.getElementById('api-content').textContent = glued));
// put it all together:
my_requests.resolve().then(requests => requests.map(addTitle));
Using it with your code - Working Example:
function Serial(promises = []) {
return {
promises,
resolved: [],
addPromise: function(fn) {
promises.push(fn);
},
resolve: async function(cb = i => i, err = (e) => console.log("trace: Serial.resolve " + e)) {
try {
for await (let p of this[Symbol.iterator]()) {}
return this.resolved.map(cb);
} catch (e) {
err(e);
}
},
[Symbol.iterator]: async function*() {
this.resolved = [];
for (let promise of this.promises) {
let p = await promise().catch(e => console.log("trace: Serial[Symbol.iterator] ::" + e));
this.resolved.push(p);
yield p;
}
}
}
}
//setup urls:
var search_urls = ["https://jsonplaceholder.typicode.com/todos/1", "https://jsonplaceholder.typicode.com/todos/2"];
var request = (url) => () => fetch(url);
let my_requests = new Serial(search_urls.map(request));
//setup glued (you don't really need to, but if for some reason you want the info stored...
var glued = "";
//setup helper function to grab title(this is necessary for my specific data)
var addTitle = (req) => req.json().then(obj => (glued += obj.title, document.getElementById('api-content').textContent = glued));
// put it all together:
my_requests.resolve().then(requests => requests.map(addTitle));
<div id="api-content"></div>
Final Note
It's likely that we will be seeing a prototypal change to the Promise object in the future that allows for easy serialization of Promises. Currently (7/15/19) there is a TC39 Proposal that does add a lot of functionality to the Promise object but it hasn't been fully vetted yet, and as with many ideas trapped within the Proposal stage, it's almost impossible to tell when they will be implemented into Browsers, or even if the idea will stagnate and fall off the radar.
Until then workarounds like this are necessary and useful( the reason why I even went through the motions of constructing this Serializer object was for a transpiler I wrote in Node, but it's been very helpful beyond that! ) but do keep an eye out for any changes because you never know!
Hope this helps! Happy Coding!
Your best bet is probably going to be building up that glued variable with recursion.
Here's an example using recursion with a callback function:
var glued = "";
requestRecursively(/* Some initial URL string */, function() {
document.getElementById('api-content').textContent = glued;
});
function requestRecursively(url, cb) {
request(url).then(function (response) {
if (/* Some condition */) {
glued += processQuery(response[0]);
var next = /* Gets next URL string */;
if (next) {
// There's another URL. Make another request.
requestRecursively(next, cb);
} else {
// We're done. Invoke the callback;
cb();
}
} else {
console.log("Done.");
}
}).catch(function (err) {
console.error(err.message);
});
}

sequential call using promise inside loop

i want to perform synchronous operation of functions using promise. I have loop that passes the data to be inserted to insert function and after inserting one row i want to check the no. of rows exists in table hence i am performing select operation.
But the issue is if there are 3 records then it inserts all 3 records and after that my select function gets executed. what i want is after insertion of one record select function gets called.
here is my pseudo code as entire code involves lot of operations
for(var i=0; data.length ; i++){
self.executeFeedbackTrack(data);
}
executeFeedbackTrack:function(callInfo){
var self=this;
return self.insertFeedbackTrack(callInfo).then(function(data){
console.log("insertFeedbackTrack status "+status);
return self.getFeedbackTrack();
});
},
getFeedbackTrack :function(){
return new Promise(function(resolve,reject){
var objDBFeedbackTrack = new DBFeedbackTrack();
objDBFeedbackTrack.selectFeedbackTrack(function(arrayCallRegisters){
if(arrayCallRegisters){
console.log("notification.js no. of feedbacks "+arrayCallRegisters.length);
resolve(arrayCallRegisters.length);
}
});
});
},
insertFeedbackTrack :function(callInfo){
return new Promise(function(resolve,reject){
var objDBFeedbackTrack = new DBFeedbackTrack();
objDBFeedbackTrack.insertFeedbackTrack(callInfo.callNumber,callInfo.callServiceType,function(status){
resolve(status);
$('#loader').hide();
});
});
}
The previous answer is good, but if you are using nodejs, or babel, or you are using only modern browsers. You can use an async-await pair, it is es8 stuff.
let insertFeedbackTrack = function(){ return new Promise(/***/)};
let getFeedbackTrack = function(){ return new Promise(/***/)};
let processResult = async function(data){
let feedbacks = [];
for(let i=0;i<data.length;i++){
let insertedResult = await insertFeedbackTrack(data[i]);//perhaps you will return an id;
let feedbackTrack = await getFeedbackTrack(insertedResult.id);
feedbacks.push(feedbackTrack);
}
return feedbacks;
}
processResult(data).then(/** do stuff */)
It looks to me like this is caused by executing a series of asynchronous inserts, and assuming that the get of insert n (inside of a .then()) is called before insert n+1 is executed. However, I'm not aware of any such guarantee, in JavaScript; all that I'm familiar with is that then n will be called after insert n, not that it would be called before insert n+1.
What I'd suggest is avoiding this mix of traditional and callback-based code, and instead put the iteration step inside getFeedbackTrack().then. Assuming this understanding of the issue is correct, then something like the following should work:
function iterate(i) {
if (i < data.length) {
obj.insertFeedbackTrack(data[i]).then(function(insertResult) {
self.getFeedbackTrack().then(function(getResult) {
// this line is the important one, replacing the `for` loop earlier
iterate(i+1);
});
});
}
}
iterate(0);
By doing that, you would guarantee that insert for the next element does not occur until the current select executes successfully.
Naturally, you may also want to restructure that to use chained .then instead of nested; I used nested rather than chained to emphasize the ordering of callbacks.
This can be solved by using a very handy JS library Ramda. Concept is to use two methods, one is R.partial and another is R.pipeP.
First create a promises array from your data array, like following.
var promises = data.map(function(i) {
return R.partial(sample, [i])
});
Then you can pass this promise to R.pipeP, so that it can be executed one after another. like below.
var doOperation = R.pipeP.apply(this, promises)
Please execute following snippet attached.
// Sample promise returning function
function sample(d) {
return new Promise(function(resolve, reject){
setTimeout(function() {
console.log('resolved for:' + d);
resolve(d);
}, 1000)
})
}
// Sample data
var data = [1, 2, 3, 4, 5]
// Converting data array to promise array
var promises = data.map(function(i) {
return R.partial(sample, [i])
});
var doOperation = R.pipeP.apply(this, promises)
doOperation();
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
So in your case, the code will look like this
var promises = data.map(function(i) {
return R.partial(self.executeFeedbackTrack, [i])
});
var doOperation = R.pipeP.apply(this, promises)
doOperation();
I use yield for such cases if using generator functions.
for(var i = 0; i < order.tasks.length; i++){
if(order.tasks[i].customer_id === 0){
var name = order.tasks[i].customer_name.split(" ")
const customers = yield db.queryAsync(
`INSERT INTO customers(
business_id)
VALUES(?)
`,[order.business_id])
}
}
Or else I use self-calling functions in case of callbacks.
var i = 0;
(function loop() {
if (i < data.length) {
task_ids1.push([order.tasks[i].task_id])
i++;
loop();
}
}());
Here's how I would sequentially call promises in a loop (I'm using ES7).
First, let's define some basic data:
const data = [0,1,2,3];
Then, let's simulate some long running process, so let's create a function that returns a Promise (you can think of this as a simulated network request, or whatever suits your needs)
const promiseExample = (item) =>
new Promise((res) => {
setTimeout(() => {
console.log('resolved ', item);
res(item);
}, 1000);
});
Now, let's create an array of promises. What the next line of code does is: for every item in the array data, return a promise factory. A promise factory is a function that wraps a certain promise without running it.
const funcs = data.map(item => async () => await promiseExample(item));
Now, the actual code starts here. We need a function that does the actual serialization. Since it has to handle an array of promiseFactories, I split it in two functions, one for the serialization of a single promise, and one for handling an array of promiseFactories.
const serializePromise = promiseFactoryList =>
promiseFactoryList.reduce(serialize, Promise.resolve([]));
const serialize = async (promise, promiseFactory) => {
const promiseResult = await promise;
const res = await promiseFactory();
return [...promiseResult, res];
};
Now, you can simply call it like this:
serializePromise(funcs).then(res => {
console.log('res', res);
});
As you can see, the code is pretty simple, elegant, functional, and doesn't need any external dependency. I hope this answers your question and helps you!
const serializePromise = promiseFactoryList =>
promiseFactoryList.reduce(serialize, Promise.resolve([]));
const serialize = async (promise, promiseFactory) => {
const promiseResult = await promise;
const res = await promiseFactory();
return [...promiseResult, res];
};
const data = [0,1,2,3];
const promiseExample = (item) =>
new Promise((res) => {
setTimeout(() => {
console.log('resolved ', item);
res(item);
}, 1000);
});
const funcs = data.map(item => async () => await promiseExample(item))
serializePromise(funcs).then(res => {
console.log('res', res);
});
I ran into this problem recently and solved it as shown below. This is very similar to the answer by #Ethan Kaminsky, but only uses callbacks. This may be useful for people avoiding promises for whatever reason.
In my application the asynchronous function may fail and can safely be retried; I included this logic because it's useful and doesn't overly complicate the routine, but it is not exercised in the example.
// Some callback when the task is complete
function cb(...rest) { window.alert( `${rest.join(', ')}` ) }
// The data and the function operating on the data
// The function calls "callback(err)" on completion
const data = [ 'dataset1', 'dataset2', 'dataset3' ]
const doTheThing = (thingDone) => setTimeout( thingDone, 1000 )
let i = -1 // counter/interator for data[]
let retries = 20 // everything fails; total retry #
// The do-async-synchronously (with max retries) loop
function next( err ) {
if( err ) {
if( ! --retries ) return cb( 'too many retries' )
} else if( ! data[++i] ) return cb( undefined, 'done-data' )
console.log( 'i is', i, data[i] )
doTheThing( next, data[i] ) // callback is first here
}
// start the process
next()

await Promises.all SyntaxError

According to this article: https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
It seems like it could be possible to use below syntax:
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
for multiple promises execution. However while using it I get Uncaught SyntaxError: Unexpected identifier.
How can i use async/await and promise.all to achieve multiple simultaneous operations executed and one resolve with a response.
-----EDITED
the function i am using inside promise.all is this one:
async function getJson(callback) {
try {
let response = await fetch('URL_LINK_HERE');
let json = await response.json();
return json;
} catch(e) {
console.log('Error!', e);
}
}
as a test field i am using google chrome Version 60.0.3112.113
Most likely your code looks something like this:
var thingsDone = await Promise.all([
Promise.resolve("eat"),
Promise.resolve("sleep")
]);
console.log(thingsDone);
This will not work because the await keyword is only valid within an async function (which the global context is not). It will simply cause a syntax error.
One way to handle this is to use it like a regular old promise and not using the await keyword:
Promise.all([
Promise.resolve("eat"),
Promise.resolve("sleep")
]).then((thingsDone) => console.log(thingsDone));
Or if you want to get fancy (or need more room to write an expressive function), wrap your logic in an async function and then handle it like a promise:
async function doThings() {
var eat = await Promise.resolve("eat");
var sleep = await Promise.resolve("sleep");
return Promise.all([Promise.resolve(eat), Promise.resolve(sleep)]);
}
doThings().then((thingsDone) => console.log(thingsDone));
This would allow you to use await as needed and is much more helpful in a more complicated function.
Or even more succinctly using an immediately-executing async function:
(async() => {
var eat = await Promise.resolve("eat");
var sleep = await Promise.resolve("sleep");
return Promise.all([Promise.resolve(eat), Promise.resolve(sleep)]);
})().then((thingsDone) => console.log(thingsDone));
torazaburo pointed me to right direction in his comments and i figured it out, this is the final code that is working:
var getJson = async function() {
try {
let response = await fetch('http://mysafeinfo.com/api/data?list=englishmonarchs&format=json');
let json = await response.json();
return json;
} catch(e) {
console.log('Error!', e);
}
}
var check_all = async function(callback) {
callback( [foo, bar] = await Promise.all([getJson(), getJson()]) );
};
check_all(function(data) {
console.log(data);
});
This works, example here: https://jsfiddle.net/01z0kdae/1/

Categories