Skip to main content
Loading...

More JavaScript Posts

//Retries maxRetries number of times, meaning that if you have 0, then it'll run the function once.
async function retryPromise(promiseFn, maxRetries = 3, delayOffset = 0, delayRandomRange = 0) {
	return new Promise((resolve, reject) => {
		promiseFn()
			.then(resolve, (error) => { //On error
				if (maxRetries <= 0) {
					return reject(error);
				} else {
					if(delayRandomRange * Math.random() + delayOffset < 1.0){
						return retryPromise(promiseFn, maxRetries - 1, delayOffset, delayRandomRange).then(resolve, reject);
					}else{
						return new Promise((resolveTwo, rejectTwo) => {
							setTimeout(() => {
								return retryPromise(promiseFn, maxRetries - 1, delayOffset, delayRandomRange).then(resolveTwo, rejectTwo);
							}, delayRandomRange * Math.random() + delayOffset);
						}).then(resolve, reject);
					}
				}
			});
	});
}

//Tests for that function.

//Returns a function that will fail numTimes times, then will return aValue
function functionThatReturnsAFunctionThatFailsACoupleTimes(numTimes, aValue){
	return async function(){
		if(numTimes == 0){
			return aValue;
		}
		numTimes--;
		throw false;
	};
}

const SMALL_NUMBER = 10;

function testTest(failNumberOfTimes){

	let functionThatFailsACoupleTimes = functionThatReturnsAFunctionThatFailsACoupleTimes(failNumberOfTimes, true);

	//Test my test
	for(let i = 0; i < (failNumberOfTimes * 2); ++i){
		function evalTest(val){
			let testTestFailedReason = "";
			if(val === undefined){
				testTestFailedReason = "Test test returned undefined for some reason.";
			}
			if((i + 1) > failNumberOfTimes){
				if(val === true){
					//We're good
				}else{
					testTestFailedReason = "Test test didn't return true when it should have.";
				}
			}else{
				if(val === false){
					//We're good
				}else{
					testTestFailedReason = "Test test didn't return false when it should have.";
				}
			}
			testTestFailedReason = testTestFailedReason || "Test test passed test case";
			console.log(testTestFailedReason, "at index", i, "where the function returned", val);
		}
		functionThatFailsACoupleTimes().then(evalTest, evalTest)
	};
}

testTest(SMALL_NUMBER);

let testCaseCounter = 1;

const throwsNoError = [
	(val)=>{
		if(val == true){
			console.log("Passed test case " + (testCaseCounter++));
		}else{
			console.error("Unexpected return value", val);
		}
	},
	()=>{
		console.error("It wasn't supposed to fail!")
	}
]

const throwsError = [
	(val)=>{
		console.error("It wasn't supposed to succeed!", val);
	},
	(val)=>{
		if(val == false){
			console.log("Passed test case " + (testCaseCounter++));
		}else{
			console.error("Unexpected return value", val);
		}
	}
];

//Runs SMALL_NUMBER times, because SMALL_NUMBER - 1 is the number of retries after the first one
let functionThatFailsACoupleTimes = functionThatReturnsAFunctionThatFailsACoupleTimes(SMALL_NUMBER - 1, true);

retryPromise(functionThatFailsACoupleTimes, SMALL_NUMBER - 1).then(...throwsNoError)

functionThatFailsACoupleTimes = functionThatReturnsAFunctionThatFailsACoupleTimes(SMALL_NUMBER - 1, true);

//Runs SMALL_NUMBER - 1 times, because SMALL_NUMBER - 2 is the number of retries after the first one
retryPromise(functionThatFailsACoupleTimes, SMALL_NUMBER - 2).then(...throwsError)

//Testing the delay. You'll have to wait a bit too.

functionThatFailsACoupleTimes = functionThatReturnsAFunctionThatFailsACoupleTimes(SMALL_NUMBER - 1, true);

//Runs SMALL_NUMBER times, because SMALL_NUMBER - 1 is the number of retries after the first one
retryPromise(functionThatFailsACoupleTimes, SMALL_NUMBER - 1, 500, 500).then(...throwsNoError)

functionThatFailsACoupleTimes = functionThatReturnsAFunctionThatFailsACoupleTimes(SMALL_NUMBER - 1, true);

//Runs SMALL_NUMBER - 1 times, because SMALL_NUMBER - 2 is the number of retries after the first one
retryPromise(functionThatFailsACoupleTimes, SMALL_NUMBER - 2, 500, 500).then(...throwsError)
class DoublyLinkedList {
  constructor() {
    this.nodes = [];
  }

  get size() {
    return this.nodes.length;
  }

  get head() {
    return this.size ? this.nodes[0] : null;
  }

  get tail() {
    return this.size ? this.nodes[this.size - 1] : null;
  }

  insertAt(index, value) {
    const previousNode = this.nodes[index - 1] || null;
    const nextNode = this.nodes[index] || null;
    const node = { value, next: nextNode, previous: previousNode };

    if (previousNode) previousNode.next = node;
    if (nextNode) nextNode.previous = node;
    this.nodes.splice(index, 0, node);
  }

  insertFirst(value) {
    this.insertAt(0, value);
  }

  insertLast(value) {
    this.insertAt(this.size, value);
  }

  getAt(index) {
    return this.nodes[index];
  }

  removeAt(index) {
    const previousNode = this.nodes[index - 1] || null;
    const nextNode = this.nodes[index + 1] || null;

    if (previousNode) previousNode.next = nextNode;
    if (nextNode) nextNode.previous = previousNode;

    return this.nodes.splice(index, 1);
  }

  clear() {
    this.nodes = [];
  }

  reverse() {
    this.nodes = this.nodes.reduce((acc, { value }) => {
      const nextNode = acc[0] || null;
      const node = { value, next: nextNode, previous: null };
      if (nextNode) nextNode.previous = node;
      return [node, ...acc];
    }, []);
  }

  *[Symbol.iterator]() {
    yield* this.nodes;
  }
}

const list = new DoublyLinkedList();

list.insertFirst(1);
list.insertFirst(2);
list.insertFirst(3);
list.insertLast(4);
list.insertAt(3, 5);

list.size;                      // 5
list.head.value;                // 3
list.head.next.value;           // 2
list.tail.value;                // 4
list.tail.previous.value;       // 5
[...list.map(e => e.value)];    // [3, 2, 1, 5, 4]

list.removeAt(1);               // 2
list.getAt(1).value;            // 1
list.head.next.value;           // 1
[...list.map(e => e.value)];    // [3, 1, 5, 4]

list.reverse();
[...list.map(e => e.value)];    // [4, 5, 1, 3]

list.clear();
list.size;                      // 0