JavaScript - How to pass a variable from one async function to another? - async-await

I have spent a good few hours on trying to figure this out but drawing a blank.
I need to pass an array from one async function to another. Problem is, I am very new to this whole async/await world.
My code is below. I need to pass elems to the step2 function
var selenium = require('selenium-webdriver');
var Builder = selenium.Builder;
var By = selenium.By;
var Key = selenium.Key;
var util = selenium.util;
var firefox = require('selenium-webdriver/firefox');
var http = require('http');
var querystring = require('querystring');
async function startBot() {
var driver = await new Builder().forBrowser('firefox').build();
await driver.get('randomSite');
if(true){//Putting this here as it may have to do with scope. I am not sure
async function step1(){
for(var p=0; p <5 ; p++){//elems is undefined
var elem1 = await driver.findElement(By.xpath("/html/body/div/div[1]")).getText();
var elem2 = await driver.findElement(By.xpath("/html/body/div/div[2]")).getText();
var elems = [elem1, elem2]; //How do I pass this array to tge step2 funtion?
}
}
if(true){//Putting this here as it may have to do with scope. I am not sure
var char1 = 1;
var char2 = 2;
//button1
async function step2(){
for (var i = 0; i < 2; i++) {
if(elems[i] == char1){//elems is undefined
await driver.findElement(By.xpath("/html/body/div/div[" + i + "]")).click().then(function(res, err){
if(err){ reject(err); };
});
break;
}
}
}
await step1();
await step2();
}
}
};
startBot();

You can pass the elems array as a parameter to the step2 function. However, you have to do some modifications:
async function step1(){
for(var p=0; p <5 ; p++){
var elem1 = await driver.findElement(By.xpath("/html/body/div/div[1]")).getText();
var elem2 = await driver.findElement(By.xpath("/html/body/div/div[2]")).getText();
var elems = [elem1, elem2];
}
return step2(elems);
}
async function step2(elems){
for (var i = 0; i < 2; i++) {
if(elems[i] == char1){
await driver.findElement(By.xpath("/html/body/div/div[" + i + "]")).click().then(function(res, err){
if(err){ reject(err); };
});
break;
}
}
}
And only use await with the step1 function:
await step1();
That's because we returned another promise step2(elems) from the step1 function. Therefore, the await keyword will have to wait for both step1 and step2. Remember that when you call an asynchronous function you always get a promise.

Define elems outside the function.

Related

How can I throwError with an rxjs Observable in this case?

I have code like this:
loadImageFile(url: string, progressCallback: (progress: number) => void): Observable<string> {
return new Observable<string>(observer => {
const xhr = new XMLHttpRequest();
const nativeWindow = this.windowRef.nativeWindow;
let notifiedNotComputable = false;
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer";
xhr.onprogress = event => {
if (event.lengthComputable) {
const progress: number = (event.loaded / event.total) * 100;
progressCallback(progress);
} else {
if (!notifiedNotComputable) {
notifiedNotComputable = true;
progressCallback(-1);
}
}
};
xhr.onloadend = function() {
if (!xhr.status.toString().match(/^2/)) {
// Here I want that the user of the Observable created at the top with
// "return new Observable" can use "pipe(catchError(...))".
}
if (!notifiedNotComputable) {
progressCallback(100);
}
const options: any = {};
const headers = xhr.getAllResponseHeaders();
const m = headers.match(/^Content-Type:\s*(.*?)$/im);
if (m && m[1]) {
options.type = m[1];
}
const blob = new Blob([this.response], options);
observer.next((nativeWindow as any).URL.createObjectURL(blob));
observer.complete();
};
xhr.send();
});
}
How can I make the xhr.onloadend act so the Observable returned by this loadImageFile method will throwError?
I believe my issue is that I am already inside new Observable, while it's the main function loadImageFile that should return throwError.
How can I overcome this?
PS: Please ignore this text: StackOverflow won't let me post this because it's mostly code, but in this case, I believe it makes sense, so I'm just writing this paragraph here to make the post validation pass :)
Thanks!
Here's the solution:
observer.error(xhr)

httpRequest inside for loop sets same value for all records

I want to build and return an array of objects from CloudCode based on a query and the result of a httpRequest done for each record.
The problem with the following (example) is that it adds the same value for all "element" objects for all records. From testing I know that the variables "outside" the promises.push(Parse.Cloud.httpRequest(.. (e.g. "countryName") are unique.
What am I missing here?
Thanks!
Parse.Cloud.define("search3", function(request, response) {
var rs = [];
var promises = [];
// Query CountryTemp class
var query = new Parse.Query('CountryTemp');
query.limit(1000);
query.exists("Country");
query.include("Country");
query.greaterThan('Month11', 25);
query.find().then(function(results) {
for (var i = 0; i < results.length; ++i) {
var element = {};
var result = results[i];
var country = result.get("Country");
var countryID = country.id;
var countryName = country.get("Name");
var temp = result.get("Month11");
promises.push(Parse.Cloud.httpRequest({
url: 'http://www.google.com'
}).then(function(httpResponse){
element.id = countryID;
element.countryName = countryName;
element.temp = result.get("Month11");
element.httpresponse = httpResponse.text.substr(0, 50);
rs.push(element);
}));
}
return Parse.Promise.when(promises);
}).then(function() {
response.success(rs);
}, function() {
response.error('error');
});
});
Found the problem, Using underscore "_each" instead of "for" fixed it:
var _ = require('underscore');
..
_.each(results, function(result) {

How to know if all uploads completed within a loop?

I have a code that works well for sending multiple files via ajax with FormData and XMLHttpRequest;
for (var i=0, j=this.files.length; i<j; i++) {
file = this.files[i];
var formdata = new FormData();
formdata.append("images[]", file);
var xhr = new XMLHttpRequest(),
upload = xhr.upload,
id = Math.floor((Math.random() * 100000));
upload.addEventListener("loadstart", function(e){
showUploadedItem(file, this.id);
});
upload.id = id;
upload.onprogress = function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
)
};
upload.onload = function(e) {
if (this.status == 200) {
console.log('');
}
};
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState ) {
console.log('');
}
};
xhr.open('post', '<?php echo Yii::app()->createUrl('url') ?>', true);
xhr.send(formdata);
}
I am sending each file as a new XMLHttpRequest object inside the loop, so I do not know when I'm getting all requests ending.
Can anyone help?
Take a look at the documentation for XMLHttpRequest.
There are a couple of options that I can think of. You could use the "loadend" callback for each of them and increment a variable outside of the loop and check for the total amount of requests that were sent in each one. Once the count reaches the total number of requests, you could perform any logic or call a function that would want to call.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest
Otherwise, setting the async parameter to false would work as well, but then you take a performance hit waiting for each one to finish before starting the others.
Based on your answer, my solution;
var x = 0;
var lenght = this.files.length;
for (var i=0, j=lenght; i<j; i++) {
// code here
var xhr = new XMLHttpRequest(),
// code here
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState && this.status == 200 ) {
x++;
if(x == lenght) {
window.setTimeout( function(){
alert('finish');
}, 1000 );
}
}
};
// code here
}
Though it is a trivial function, it works.

How to make an ajax call asynchronous?

I was trying to retrieve CRM records using Ajax calls.
function RetrieveCrmRecords(entName, fields, filter, callback, orderby, errcallback) {
///<summary>
/// function to Retrieve Multiple CRM records.
///</summary>
//debugger;
var async = !!callback;
var setEntityName = entName + 'Set';
var _callback = callback;
filter = (filter) ? "&$filter=" + filter : '';
var query1 = CrmServerUrl + ODATA + "/";
var query2 = setEntityName + "()" + "?";
var queryUrl = query1 + query2;
if (fields != null) queryUrl += "$select=" + fields.join(',');
if (orderby != null) {
if (fields != null) {
queryUrl += '&';
}
queryUrl += "$orderby=" + orderby;
}
queryUrl += filter;
var performRequest = function (queryUrl, fnCallback) {
var async = !!fnCallback;
var opts = { url: queryUrl }
return _makeRequest(opts, async, function (data) {
var nextData = data.__next || null;
var resultsData = data.results || data;
var responseData = { 'results': resultsData, 'next': nextData }
if (nextData) {
responseData.LoadNext = function (callback) {
return performRequest(nextData, callback);
};
}
if (async) {
fnCallback(responseData);
}
else {
return responseData;
}
}, errcallback);
};
return performRequest(queryUrl, callback);
}
As I don't have that much idea about ajax calls, its hard to make this function Asynchronous for me.
Experts please help me to understand that this function is synchronous because of var async = !!callback; this?
If in place of this line I write var async=true; can it make this function asynchronous?
Thanks in advance.
I think i got you exactly what you are asking for.
Please don't get look into this file from where you have copied and pasted this function.
This will make you confuse if you are new for this.
Just call the function from your .js File like this.
function RetrieveCrmRecords(entName, fields, filter, calledForAsync, orderby, errcallback) {
//Your Code
}
function calledForAsync()
{
//Your Code
}
When Operation in RetrieveCrmRecords() will completed rest code will execute finely and then it will come into the calledForAsync().
This is called Async Call.
I hope you were asking for this.
Thanks,
Anish.

Pass jQuery event to default on-eventhandler

I've written a function to call the default jQuery.fn.on-handler, after a given number of fired events. Now I stuck, because the original event will not passed to the function, any ideas how to improve this?
;(function ($) {
var oldOn = $.fn.on,
i = 0;
$.fn.on = function () {
var args = arguments,
j = args.length;
for (var last in args);
while (j--) {
if ($.isFunction(args[j]) && !isNaN(args[last])) {
var oldFn = args[j],
after = args[last];
args[j] = function () {
i++;
if (i === after) {
oldFn.call();
i = 0;
}
};
}
}
if (!isNaN(args[last])) delete args[last];
return oldOn.apply(this, arguments);
};
})(jQuery);
// call the plugin and fire the `fn` after each 20 mousemoves
$(document).on('mousemove', function (e) {
console.log(e); // undefined
}, 20);
As you can see, will the following work without problems:
var oldOn = $.fn.on;
$.fn.on = function () {
return oldOn.apply(this, arguments);
};
$(document).on('click', function(e){
console.log(e) // jQuery.Event
});
Where's the mistake, how can i get this to work?
Update
I got it much simpler now: https://github.com/yckart/jquery.unevent.js
You're not passing the arguments from your callback wrapper function to the original callback function.
args[j] = function (*HERE*) {
i++;
if (i === after) {
oldFn.call(*TO HERE*);
i = 0;
}
};
Try replacing oldFn.call(); with oldFn.apply(this, [].slice.call(arguments)); to carry them over (and keeping up jQuery's this).
Edit: http://jsfiddle.net/QFyhX/
I think
for (var last in args);
should be
var last = args[args.length-1];

Resources