資訊內容
控制Scratch異步代碼的執行順序
你是否在編寫項目時遇到過一些棘手的BUG,比如邏輯明明是通順的,但是執行結果卻不符預期。又如兩段代碼完完全全一模一樣,但是結果卻大相徑庭。這極有可能是代碼的執行順序沒有得到控制所導致的,這是一些初學者常常會遇到的問題。本文將分析這種代碼執行順序失控的原因及其應對方法。
01
依照慣例,先來看幾個案例。
《恐龍吃蘋果》
舞臺布局
恐龍代碼
使用鍵盤方向鍵控制恐龍移動,點擊綠旗使恐龍回到起始位置,準備進行下一次游戲。
蘋果代碼
判斷蘋果是否碰到恐龍,一旦碰到則隱藏,當綠旗被點擊時將蘋果切換至顯示狀態,準備進行下一次游戲。
案例很普通,代碼也普通得不能再普通了,都進行了初始化操作,甚至可以說代碼是比較規范的。那么來看一下實際運行效果。
案例效果
注意到問題所在了嗎?在圖中,一共點擊了三次綠旗,第一次,啟動程序,控制恐龍移動,蘋果被恐龍吃掉-隱藏;第二次點擊綠旗,重啟程序,恐龍確實回到初始位置了,但是,明明設置了顯示狀態的初始化,蘋果卻并沒有出現。第三次點擊綠旗才出現。
問題是,為什么第二次點擊綠旗時,蘋果沒有按照預想的那樣,切換成顯示狀態呢?
在Scratch中遇到BUG時,有很多種調試方法,這次介紹一種變量法,通過變量來判斷某處代碼是否執行、執行次數。
新建變量“score”,在蘋果代碼中增加【將(score)增加(1)】
為了調試BUG,因此在這里不對變量做初始化。
調試效果
變量score初始值為0,在第一次點擊綠旗,被恐龍吃掉后,score的值變為1,此時再次點擊綠旗重啟程序,恐龍回到初始位置,蘋果沒有顯示,而score的值此時變為2,說明畫圈處的代碼被執行了兩次。
所以,蘋果并不是沒有顯示,而是顯示后再一次碰到恐龍,再次隱藏。唯一合理的解釋是,在第二次點擊綠旗時,蘋果的代碼被先執行了,而此時恐龍并沒有回到初始位置,因此蘋果再次碰到恐龍,再次隱藏。這時候再執行恐龍的代碼,恐龍回到初始位置,為時已晚,蘋果已經被恐龍“誤食”了。
在Scratch中,看似同時執行的代碼,實則是有先后順序的。兩段代碼沒有按照預想的先后順序執行,導致程序初始化時出現BUG。
很多初學者經常會遇到這樣的問題,有的程序點擊一次是無法正常運行的,第二次點擊才會正常。大多數情況其實和上文中展示的這個案例屬于同一種情況。如果再次遇到類似這樣的情況,就要好好考慮一下是不是由于沒有控制好代碼的先后執行順序而導致初始化BUG。
02
這個問題應該如何解決呢?既然是代碼執行順序不受控制,那么最簡單的方法就是通過【等待()秒】積木來調整順序。我們希望的是恐龍先“離開事發地點”,回到初始位置,再執行蘋果是否碰到恐龍的代碼,只需要在點擊綠旗后,等待一段短暫的時間再執行這段代碼即可。
至于等待的時間,設置成0.1還是0.01其實都可以,但是在這里我建議將數值設為0,即【等待(0)秒】。兩段當綠旗被點擊積木下的代碼的先后執行順序間隔非常短,等待0秒積木足以改變其順序。因為【等待()秒】積木會刷新屏幕,而刷新屏幕相對來說耗時較長(參見淺談Scratch的舞臺刷新機制 Part 2——在常規積木中的應用)。
加入【等待(0)秒】后,蘋果初始化正常
這在我看來有兩點意義,一是副作用最小,我們的目的是控制程序運行的先后順序,但是如果等待的時間過久,會造成明顯的卡頓,因此在能保證代碼運行順序的前提下,時間越短越好。二是起到一種標志作用,這種特殊的用法我們不妨約定俗成地將其視作為解決這類BUG的標志,一旦看到這樣的用法,就知道是用來控制代碼執行順序的。
關于【等待(0)秒】還可以參照科技傳播坊的疑難雜癥視頻 vol.41 《等待0秒的意義》。
03
BUG是解決了,但是在《恐龍吃蘋果》這個案例中,為什么是先執行蘋果的代碼再執行恐龍的代碼?而不是反過來呢?是什么決定了代碼的執行順序?
為了更直觀地表現代碼的執行順序,我們換一個更簡單的案例,通過變量來展現執行順序。
圖層順序對于異步代碼執行順序的影響
初始狀態下,橘貓的代碼是將變量設為0,圖層在后,藍貓的代碼是將變量設置為1,圖層在前。運行結果為0,表明藍貓的代碼先執行了,橘貓后執行,將變量覆蓋為0。
通過鼠標拖拽改變圖層順序,將橘貓圖層置于藍貓前面。運行結果為1,表明橘貓的代碼先執行了,藍貓后執行,將變量覆蓋為1。
通過實驗我們可以得出以下結論:
不同角色的異步代碼執行順序如下:角色圖層在前的先執行,圖層在后的后執行。
為排除鼠標拖拽可能產生的其他因素,通過代碼調整圖層順序,結論依舊成立。
04
盡管調整圖層順序是一種可控的、確定的能控制異步代碼執行順序的方法,但是編寫程序的我們不可能通過手動拖拽角色來控制代碼執行順序。萬一體驗者在非全屏模式下不小心拖拽了某個角色,改變了執行順序而導致BUG。代碼明明完全一樣,但就是無法正常運行,那將會是一件多么尷尬的事。(下次再遇到這樣的情況可以考慮一下是否是因為圖層順序影響了代碼執行順序,而又沒有很好地控制執行順序)
為控制代碼執行順序,上文中也提到了,可以使用【等待(0)秒】積木來解決,這種方法簡單直接,且對原代碼的改動最小,建議新手使用。
但是這是一種“把代碼寫死”的做法,在此給追求優質代碼的scratchers提供一種更完美的思路——消息,利用消息來控制代碼的執行順序。
橘貓代碼
藍貓代碼
通過【廣播()并等待】實現同步
隨手畫的流程圖
控制代碼的執行順序,你學會了嗎?
聲明:本文章由網友投稿作為教育分享用途,如有侵權原作者可通過郵件及時和我們聯系刪除
