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