Prototipicality judgment experiment: issues with JavaScript async functions
Hi all,
I am trying to implement a sorting algorithm guided by the choices of participants. I want participants to order a series of images as more or less representative of a category (e.g. food, vehicles, animals). At every trial, the algorithm selects the two images to present to the participant and then waits for the user input. Then based on that input, select the next two images to present.
So I need the sorting algorithm to wait for the user input at every trial before proceeding. To achieve that, I used JavaScipt async functions.
I was able to implement a working version using the Quick Sort algorithm. Here is the crucial inline JavaScript code (I attach a simplified version in which I ask the user to sort numbers from 1 to 10):
// Create an async function that returns a promise
const getUserInput = async () => {
// Create a promise object
let promise = new Promise((resolve, reject) => {
// Add an event listener for the keydown action
document.addEventListener("keydown", function (e) {
// Get the key that was pressed
let key = e.key;
// If the key is "z" or "m", resolve the promise with the key
if (key === "z" || key === "m") {
resolve(key);
}});
});
// Return the promise object
return promise;
};
const quickSort = async (arr) => {
if (arr.length <= 1) {
return arr;
}
let pivot = arr[0];
let leftArr = [];
let rightArr = [];
for (let i = 1; i < arr.length; i++) {
vars.destra = arr[0]
vars.sinistra = arr[i]
// Wait for the user to press "z" or "m"
let input = await getUserInput();
// Push the element to the left or right array based on the input
if (input === "z") {
leftArr.push(arr[i]);
} else if (input === "m") {
rightArr.push(arr[i]);
}
}
console.log([...leftArr, pivot, ...rightArr])
return [...(await quickSort(leftArr)), pivot, ...(await quickSort(rightArr))];
};
(async () => {
vars.numbers_sorted = await quickSort(vars.numbers);
// console.log(vars.animal_sorted);
if (vars.numbers_sorted.length > 1){
vars.procedi = 1
}// Should print [1,2,3,4,5,6,7,8,9,10]
})();
The quick sort algorithm is not ideal for me because it repeats trial after trial many many times one of the two items presented. Merge Sort would be perfect for me but, I am not able to make it work. Code:
// Create an async function that returns a promise
const getUserInput = async () => {
// Create a promise object
let promise = new Promise((resolve, reject) => {
// Add an event listener for the keydown action
document.addEventListener("keydown", function (e) {
// Get the key that was pressed
let key = e.key;
// If the key is "z" or "m", resolve the promise with the key
if (key === "z" || key === "m") {
resolve(key);
}
});
});
// Return the promise object
return promise;
};
// This function merges two sorted subarrays into one sorted array
const merge = async (left, right) => {
let arr = [];
// Break out of loop if any one of the array becomes empty
while (left.length && right.length) {
vars.sinistra = left[0]
vars.destra = right[0]
console.log('Inside merge loop, var destra: '+vars.destra)
console.log('Inside merge loop, var sinistra: '+vars.sinistra)
// Wait for the user to press "z" or "m"
let input = await getUserInput();
// Pick the smaller among the smallest element of left and right subarrays
if (input === "z") {
arr.push(left.shift());
} else if (input === "m") {
arr.push(right.shift());
} else {
// Handle invalid input
alert("Invalid input. Please press m or z.");
}
}
// Concatenate the leftover elements
// (in case we didn't go through the entire left or right array)
return [...arr, ...left, ...right];
}
// This function recursively divides the array into smaller subarrays
// and then calls the merge function to sort and merge them
const mergeSort = async (array) => {
const half = array.length / 2;
// debug
vars.counter += 1
if (vars.counter > 2){
console.log('Inside mergeSort, var.destra: '+vars.destra)
console.log('Inside mergeSort, var.array: '+vars.array)
}
// Base case
if (array.length < 2) {
return array;
}
const left = array.splice(0, half);
return await merge(await mergeSort(left), await mergeSort(array));
}
(async () => {
vars.numbers_sorted = await mergeSort(vars.numbers);
// console.log(vars.animal_sorted);
if (vars.numbers_sorted.length > 1){
vars.procedi = 1
}// Should print [1,2,3,4,5,6,7,8,9,10]
})();
In the case of Merge Sort, the variables "destra" and "sinistra", which then should be used to show the numbers in the sketchpad, are not assigned before the sketchpad preparation.
Experiment files:
I am sorry for the readability problems in the code snippets attached here. In the opensesame Javasctipr editor experiment the visualization is better.
Best,
Dami
Comments
Fun story:
turns out I had already fixed the problem, but created another (with the same error message!) by adding a console.log to debug the first. Even funnier is that to share the code here, I deleted the console.log that produces the error, so if you try the code it will work. (If you run the files downloaded from Dropbox you should still delete the console.log() from the MergeSort inline script.)
Take home message: always share your work.
Best,
Dami