I want to conditionally break out of a loop like this..
for(let i = 0; i < 3; i++) {
exampleFunction().then(result => {
res = 0 ? i = 3 : null
})
}
I want exampleFunction to run at least 3 times unless it gets the desired result, in which case I want it to stop running.
exampleFunction runs asynchronously. The only way to get it working is using async/await.
const iterateWithExampleFunction = async () => {
for (let i = 0; i < 3; i++) {
console.log('before', i)
await exampleFunction().then(result => {
i = result === 0 ? 3: i;
});
console.log('after', i)
}
};
const exampleFunction = async () => {
return 0;
}
iterateWithExampleFunction();
You can have a count on the outer scope and then do the async call.
let count = 0;
function executeCall() {
exampleFunction().then(result => {
// do something with the result
if (result !== 0 && count !== 3) {
count += 1;
executeCall();
}
});
}
Just await the result, than break:
(async function() {
for(let i = 0; i < 3; i++) {
const result = await exampleFunction();
if(result === 0) break;
}
})();
Hopefully this gives you some ideas
async function poll(f, threshold = 3) {
if (!threshold) {
throw new Error("Value not found within configured amount of retries");
}
const result = await f();
if (result >= 0.5) {
return result;
} else {
return await poll(f, threshold - 1);
}
}
async function task() {
return Math.random();
}
poll(task).then(console.log).catch(console.error);
Related
I want to condition the string that I Inputted value ("ello") and variable("hello").
If It found in string("hello"), the return value should be "ello".
If not found, the return value should be -1.
But it returned "llll" 4 times because of condition (strs[i] == arrayS[tempVal]).
How can I get the correct answer as mentioned above?
var stres = "hello";
var strs = [...stres];
function searchStr(s) {
let arrayS = [...s];
let tempVal = 0;
let tempStr = [];
while (tempVal < arrayS.length) {
for (let i = 0; i < strs.length; i++) {
if (strs[i] == arrayS[tempVal]) {
tempStr.push(arrayS[tempVal]);
}
}
tempVal++;
}
return tempStr;
}
const res = searchStr("ello");
console.log('res', res)
According to you, logic is correct just break the for a loop when the condition is fulfilled. Check below snippet and console output.
var stres = "hello";
var strs = [...stres];
function searchStr(s) {
let arrayS = [...s];
let tempVal = 0;
let tempStr = [];
while (tempVal < arrayS.length) {
for (let i = 0; i < strs.length; i++) {
if (strs[i] == arrayS[tempVal]) {
tempStr.push(arrayS[tempVal]);
break;
}
}
tempVal++;
}
return tempStr;
}
const res = searchStr("ello");
const resS = res.join('');
console.log('res = ', res);
console.log('resS = ', resS);
I'm trying to convert callbacks to async/await, but found that async/await is much slower than the existing callbacks. Can anyone see what's wrong with my async/await?
for (var i = 0; i < balance; i++) {
tokenOfOwnerByIndex().call(i).then((id) => {
tokenURI().call(id).then((uri) => {
console.log(uri);
});
});
}
for (var i = 0; i < balance; i++) {
var id = await this.getTokenOfOwnerByIndex(i);
var uri = await this.getTokenURI(id);
console.log(uri);
}
In the first version tokenOfOwnerByIndex is called returning a promise. You attach a callback via then, and the loop continues. The promise will eventually resolve, but your for loop is done long before that.
When you use await, you are blocking following code, until the promise resolves. This means that each call to tokenOfOwnerByIndex has to resolve, before the for loop continues.
See my code for an example.
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
console.time('promise');
let c = 10;
for (let i = 0; i < 10; i++) {
sleep(100)
.then(() => {
c--;
if (c === 0) {
console.timeEnd('promise');
}
});
}
console.time('await');
(async () => {
let c = 10;
for (let i = 0; i < 10; i++) {
await sleep(100);
c--;
if (c === 0) {
console.timeEnd('await');
}
}
})();
Goal:
I want to create a generator function that is being invoked inside setInterval(), and console.log 1 to 10.
the problem:
In order to clearInterval() at the end I need a condition to check if gen.next().done === true.
but every time the condition runs it actualy calls another .next()
so so final print i get is:
1 3 5 7 9 undefined
How do I set a done == true condition without calling .next() ?
function* myGen(){
let counter = 0;
for(let i = 0 ; i <= 10; i++){
yield counter++;
}
}
const gen = myGen();
const start = setInterval(() => {
if(gen.next().done){
clearInterval(start);
} else {
console.log(gen.next().value);
}
}, 1500)
You remember the object in a variable rather than calling next a second time:
function* myGen(){
let counter = 0;
for(let i = 0 ; i <= 10; i++){
yield counter++;
}
}
const gen = myGen();
const start = setInterval(() => {
var next = gen.next(); // *** Save it here
if(next.done){ // *** Use it here...
clearInterval(start);
} else {
console.log(next.value); // *** ...and here
}
}, 150)
You can alternatively use for..of loop, setTimeout(), async/await to avoid the need to check for .done property value
function* myGen() {
let counter = 0;
for (let i = 0; i <= 10; i++) {
yield counter++;
}
}
const gen = myGen();
(async() => {
for (let n of gen) {
await new Promise(resolve => {
setTimeout(() => {
console.log(n);
resolve()
}, 1500)
})
}
})();
Another way is to use the relatively new AsyncGenerator feature
https://github.com/tc39/proposal-async-iteration
I think it abstracts the problem nicely (creating an iterator that sleeps in between each iteration).
async function* sleepGenerator(numSleeps, sleepMillis) {
for (let i = 0; i < numSleeps; i++) {
await sleep(sleepMillis);
yield {i, numSleeps, sleepMillis};
}
}
function sleep(sleepMillis) {
return new Promise(resolve => setTimeout(resolve, sleepMillis));
}
(async function run() {
for await (const iterMeta of sleepGenerator(5, 500)) {
console.log(iterMeta);
}
})();
just, store the nextValue
function* myGen(){
let counter = 0;
for(let i = 0 ; i <= 10; i++){
yield counter++;
}
}
const gen = myGen();
const start = setInterval(() => {
let nextValue = gen.next();
if(nextValue.done){
clearInterval(start);
} else {
console.log(nextValue.value);
}
}, 1500)
function* myGen(){
let counter = 0;
for(let i = 0 ; i <= 10; i++){
yield counter++;
}
}
const gen = myGen();
const start = setInterval(() => {
var genObj=gen.next();//keep next result as an object to avoid use next method twice
if(genObj.done){
clearInterval(start);
} else {
console.log(genObj.value);
}
}, 1500)//I spent an hour learning this,late but get some konwledge,so,thanks.
My code will log all 10 lines in the order that I want (descending triangle), but I need it to delay 1 second before logging each successive line. I tried putting a setTimeout before the for loop, but that just caused a 1 second delay before printing all 10 lines concurrently.
function minusTen(num) {
var arr = '';
for (var i = num; i > 0; i--) {
arr += '*';
}
var newArr = arr.split('');
for (var j = num; j > 0; j--) {
newArr.pop();
console.log(newArr.join(' '));
}
}
minusTen(10);
I can use jQuery but I'd like to avoid having to implement Bootstrap if possible.
Thank you!
you can use setTimeout for it but then you will have to keep setTimeout inside the for loop. you can also use setInterval here and clear the interval if num becomes 0. something like this:
function minusTen(num) {
var arr = '';
for (var i = num; i > 0; i--) {
arr += '*';
}
var newArr = arr.split('');
var interval = setInterval(function(){
newArr.pop();
console.log(newArr.join(' '));
num--;
if(!num)
clearInterval(interval);
}, 1000)
}
minusTen(10);
You can use a function. Check the .length of newArr, if greater than 0, call function again
function minusTen(num) {
var arr = '';
for (var i = num; i > 0; i--) {
arr += '*';
}
var newArr = arr.split('');
function fn() {
if (newArr.length)
setTimeout(function() {
console.log(newArr.join(" "));
newArr.pop();
fn()
}, 1000)
else
console.log("done, newArr.length:", newArr.length);
}
fn()
}
minusTen(10);
function minusTen(num) {
var arr = '';
for (var i = num; i > 0; i--) {
arr += '*';
}
var newArr = arr.split('');
function printLine(counter){
var k = counter;
window.setTimeout(function(){
console.log(newArr.join(' '));
newArr.pop();
}, k*1000);
console.log(k);
}
for (var j = num; j > 0; j--) {
printLine(j);
}
}
minusTen(10);
It's straightforward with async/await. delay holds the execution of the code for a specified amount of time.
async function minusTen(num) {
var arr = '';
for (var i = num; i > 0; i--) {
arr += '*';
}
var newArr = arr.split('');
for (var j = num; j > 0; j--) {
newArr.pop();
await delay(1000)
console.log(newArr.join(' '));
}
}
function delay(time) {
return new Promise((resolve) => setTimeout(resolve, time))
}
minusTen(10);
You can use setTimeout with an offset. Just add whatever parameters you need to the log function.
function log(offSet) {
setTimeout(() => {
const str = new Array(offSet + 1).join('*');
console.log(str);
}, 1000 * offSet);
}
for(let i = 1; i < 11; i ++) {
log(i);
}
https://jsfiddle.net/ycreaL9w/
If you wanted to reduce your code footprint a little you could do something like this:
const printStars = (n) => {
// Make sure we don't try to print zero stars
if (n > 0) {
// Fill an array with n stars
const arr = Array(n).fill('*').join(' ');
console.log(arr);
// After a second, reduce n by 1 and call
// the function again
setTimeout(() => printStars(--n), 1000);
}
}
printStars(10);
DEMO
It's worth pointing out here, however, that IE/Opera don't support Array.fill.
If you need to support them use an for/loop like in your example. Here I've separated out that code into its own function.
const getStars = (n) => {
let arr = [];
for (let i = 0; i < n; i++) {
arr.push('*');
}
return arr.join(' ');
}
const printStars = (n) => {
if (n > 0) {
console.log(getStars(n));
setTimeout(() => printStars(--n), 1000);
}
}
DEMO 2
Based on this example - vo/examples/9-pipeline-composition.js, how would I return yield a promise for each iteration of this for loop?
At the moment the loop runs once and yields a single promise.
function * get (urls) {
for (var i = urls.length - 1; i >= 0; i--) {
console.log(urls[i])
return yield http.get(urls[i])
}
}
function status (res, params) {
return res.status
}
let scrape = vo(get(['http://standupjack.com', 'https://google.com']), status)
vo([ scrape ])
.then(out => console.log('out', out))
.catch(e => console.error(e))
When u do the return inside the for loop, the loop breaks and returns the result and the loop wont move forward. You can call a function inside the for loop which handles the result and not return it.
function * get (urls) {
for (var i = urls.length - 1; i >= 0; i--) {
console.log(urls[i])
let result = yield http.get(urls[i])
yield handleResult(result)
}
}
Orelse u can push each of the results in an array and return all of then together at the end
function * get (urls) {
let resArr = []
for (var i = urls.length - 1; i >= 0; i--) {
console.log(urls[i])
let result = yield http.get(urls[i])
resArr.push(result)
}
return resArr
}