編輯,更新:
。我現在可以在所有瀏覽器上100%地重現這個錯誤,在任何情況下都是如此。通過大量的試驗和錯誤,我發現在調查和歡迎界面之后的第一個指令界面(玩家的角色被分配給他們的地方)快速點擊右鍵,我可以讓這個錯誤100%地出現。我的猜測是,快速按鍵導致事件監聽器在它應該被觸發之前被多次觸發,導致一些函式引數因某種原因而未被定義。不知道該如何進行。在使用 在p5.js中撰寫了一個視頻游戲,并將其托管為Google Firebase網路應用。我使用一個自定義的事件監聽器來回圈播放視頻游戲的關卡。大約30%-40%的用戶報告了一個錯誤,即游戲在沒有用戶輸入的情況下快速回圈通過所有關卡。我只能在大約10%的時間里重現這個錯誤,而且只在特定情況下。通常情況下,當該錯誤發生時,控制臺或通過錯誤報告服務不會出現錯誤資訊。
我正在網上進行一項心理學研究,使用一種名為Prolific的服務來招募受試者。該研究包括幾項調查,然后是一個視頻游戲任務。我使用p5.js撰寫了這個視頻游戲。該研究有幾個不同的任務條件,它們被編程為不同的p5草圖。為了回圈進行適當的試驗序列,我使用了一個自定義撰寫的事件監聽器,當結束當前試驗的適當條件得到滿足時,該監聽器就會啟動,洗掉當前的草圖并開始下一個試驗。我通過谷歌Firebase將調查和視頻游戲作為一個網路應用托管。該研究的作業方式是,Prolific上想要參與的用戶被引導到網路應用的URL(如果你私下給我留言,我可以提供這個URL)。
大約30%-40%的研究物件報告了一個不尋常的bug,我很難再現。游戲將在幾個試驗中順利運行,然后突然崩潰,在沒有任何用戶輸入的情況下快速回圈通過所有剩余的試驗,直到達到研究的終點。我試圖在所有主要的瀏覽器(Firefox、Chrome、Safari)和所有主要的作業系統(Windows、Mac OS、Linux)上,在幾臺不同的機器上重現這個錯誤。在所有情況下,我只有10%的時間能夠重現該錯誤,即使如此,也只是在特定情況下(見下文)。
絕大多數情況下(在我和用戶端),在崩潰期間,控制臺中沒有出現未處理的例外(錯誤訊息),也沒有被我的錯誤監控服務報告(Sentry.io)。)
如下面的示例代碼所示,一個函式引數
在 Safari 和 Firefox 中,除非從 Prolific 啟動應用程式,否則該錯誤不會出現,這一點具有潛在意義。Prolific在URL的末尾附加了一個查詢字串,使主體得以識別,從而使他們的時間可以得到補償。我不確定這為什么會成為一個問題,但我可以看到一個奇怪的情況,即查詢字串以某種方式擾亂了與資料庫的通信。
另外,我使用 非常感謝您對此事的幫助,我正一籌莫展地試圖解決這個問題。
uj5u.com熱心網友回復: 在查看了原始的源代碼之后,我們確定這個錯誤很可能是由于在呼叫 這個故事的寓意是,你需要在你的用戶輸入處理函式中采取防御措施,而不是假設
標籤:sleep()時,在按下方向鍵后加一個延遲是否有幫助?
TL; DR
較長的解釋
。
NetworkError when attempting to fetch resource / Failed to fetch resource。我不確定為什么會出現這個錯誤,而且它在應用程式的成功運行和崩潰期間都斷斷續續地出現,這使我相信這不是罪魁禍首。唯一被加載的資源是Web應用程式的public目錄下的影像。然而,有時在崩潰的運行中,在崩潰時(我無法確定是在崩潰點之前、期間還是之后),有時應該加載的影像沒有顯示出來(但P5沒有報告錯誤)。
a被用來確定在當前試驗的畫布上繪制哪個草圖。我有時會在應用程式的崩潰運行中得到錯誤a is undefined。這個錯誤對我來說沒有意義,因為根據Javascript范圍鏈,我作為引數a傳遞給函式defineSketch(a)的變數param_seq[i]應該有一個全域范圍,并且肯定被定義了。我的猜測是,這要么是罪魁禍首,要么是由于崩潰而產生的一些衍生錯誤。但我唯一能想到的是,偶爾會發生一些奇怪的代碼異步評估或其他一些時間問題,導致defineSketch的引數未被定義,導致崩潰。但我不知道如何驗證或除錯這個問題。
潛在的相關細節
我只能在以下情況下重現這個bug:$作為一個屬性的名稱。我用于在 Web 應用程式中收集調查資料的一個 Javascript 庫采用了 jQuery,而我最近意識到 $ 是 jQuery 的一個快捷方式,因此這有可能導致一個問題。
最小的作業實體
視頻游戲很復雜,涉及大量的代碼,所以很難寫出一個最小的作業實體。下面的示例代碼包含了用于回圈瀏覽不同試驗的自定義事件監聽器的邏輯,以及生成p5草圖(試驗)的函式,每個草圖都有不同形式的用戶互動或試驗結束的條件。雖然在MWE中沒有調查,但我包括了為它們編程所需的Javascript庫,以備不時之需。
。
//listed variable
//我們設定了一個監聽變數,當bool的值發生變化時,這個監聽變數將被觸發。
let sketchIsRunning = {
$: false,
listener: function(val) {},
set bool(val) {
this.$ = val;
this.listener(val)。
},
get bool() {
return this.$。
},
registerListener: function(listener) {
this.listener = listener。
}
};
/* Function to define sketch with parameter 'a' */
function defineSketch(a) {
switch (a) {
case 0:
return function(p) {
let x = 100;
let y = 100;
p.setup = function() {
p.createCanvas(700, 410) 。
};
p.draw = function() {
p.background(0)。
p.fill(255)。
p.rect(x, y, 50, 50)。
};
/* 滑鼠按下時洗掉草圖 */
p.mousePressed = function() {
p.remove()。
sketchIsRunning.bool = !sketchIsRunning.bool
console.log('sketch is running ? ', sketchIsRunning.bool)
};
};
break。
case 1:
return function(p) {
let x = 200;
let y = 200;
p.setup = function() {
p.createCanvas(700, 410)。
//顯示草圖的時間長短sketch_length = p.random(1e3, 5e3) 。
// 草圖的開始時間sketch_start = window.performance.now()。
};
p.draw = function() {
p.background(0)。
p.fill(255)。
p.ellipse(x, y, 50, 50) 。
p.rect(y, x, 50, 50)。
/* 在隨機時間后洗掉草圖 */。
if (window.performance. now() - p.sketch_start >= p.sketch_length) {
p.remove()。
sketchIsRunning.bool = !sketchIsRunning.bool
console.log('sketch is running ?', sketchIsRunning.bool)
}
};
};
break。
case 2:
return function(p) {
let x = 0;
let y = 0;
p.setup = function() {
p.createCanvas(700, 410) 。
};
p.draw = function() {
p.background(0)。
p.fill(255)。
p.ellipse(x, y, 50, 50)。
};
/* 按鍵時洗掉草圖 */
p.keyPressed = function() {
p.remove()。
sketchIsRunning.bool = !sketchIsRunning.bool
console.log('sketch is running ? ', sketchIsRunning.bool)
};
};
break。
default:
console.log("No match"/span>)
break。
}
}
/* Initialize sketch variable */; }
let trialSketch;
/* 引數陣列 */
let param_seq = [0, 1, 2] 。
//我們嵌套了對函式本身的呼叫來回圈瀏覽param.seq陣列。
const instanceP5sketches = (i =0) => {
sketchIsRunning.$ = !sketchIsRunning.$;
trialSketch = defineSketch(param_seq[i])。
new p5(trialSketch)。
sketchIsRunning.registerListener(function(val) {
if (param_seq.length - 1 >= i) {
instanceP5sketches(i 1)。
} else {
console.log('No more sketches. ' )
}
});
}
//開始回圈瀏覽草圖。
instanceP5sketches();
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" class="snippet-box-edit snippet-box-result" frameborder="0"></iframe>
<! DOCTYPE html>
<html>
<head>
<!--加載調查格式腳本-->
<script src="https://unpkg. com/jquery">/span></script>/span>
<script src="https://unpkg.com/[email protected]/survey.jquery.min.js"/span>> </script>>
< link href="https://unpkg.com/[email protected]/modern.css"/span> type="text/css" rel="styleheet" />
<!--載入p5.js -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"/span>> </script>>
</head>
<body></body>
</html>setup()函式之前,實體模式的草圖的keyPressed事件發生的結果。
let currentSketch;
function sketch1(p){
let c = 0;
p.setup = () => {
p.createCanvas(p.windowWidth, p.windowHeight) 。
p.noLoop()。
};
p.draw = () => {
p.text('Press the space bar 3 times to continue...' , 10, 10)
};
p.keyPressed = (e) =>/span> {
if (p.key === ' '/span>) {
if ( c >= 3) {
//切換到草圖2
p.remove()。
currentSketch = new p5(sketch2)。
}
}
e.preventDefault()。
return false。
};
}
function sketch2(p) {
let bg;
let events = [] 。
let color = 'red;
p.preload = () => {
//加載一個圖片以延遲設定,防止快取。
bg = p.loadImage(`https://www.paulwheeler.us/files/windows-95-desktop-background.jpg?r=${p.random()}`) 。
};
p.setup = () => {
p.createCanvas(p.windowWidth, p.windowHeight) 。
events.push('green')。
color = 'blue'。
};
p.draw = () => {
p.clear()。
p.image(bg, 0, 0, p.width, p.height) 。
let x = 5;
let y = 5;
for (let e of events) {
p.fill(e)。
p.square(x, y, 20)。
x = 25;
if (x 25 >= p.width) {
x = 5;
y = 20;
}
}
};
p.keyPressed = (e) => {
if (p.key === ' '/span>) {
events.push(color)。
}
e.preventDefault()。
return false。
};
}
currentSketch = new p5(sketch1);
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" class="snippet-box-edit snippet-box-result" frameborder="0"></iframe>
<script src="https://cdnjs. cloudflare.com/ajax/libs/p5.js"></script> setup()函式已經完成。
