快速入門:在使用 JavaScript 的 Windows 執行階段應用程式中排程工作

Applies to Windows and Windows Phone

Scheduler 可讓使用 JavaScript 的 Windows 執行階段應用程式執行背景工作時不會打斷應用程式的前景工作 (例如動畫)。這有助於減輕讓使用者感覺沒有回應或「不順暢」的使用經驗,甚至可能縮短啟動時間。 這個快速入門說明如何在適用於 JavaScript 的 Windows Library 內,使用 Scheduler 物件來排程具有優先順序的背景工具。

注意  如需更多示範如何使用 Scheduler 的範例和範例程式碼,請參閱 HTML 排程器範例

先決條件

針對這個快速入門,您必須可以使用 Windows 8.1 或 Windows Phone 8.1 中的 WinJS,來建立基本的使用 JavaScript 的 Windows 執行階段應用程式。如果建立您的第一個應用程式時需要協助,請參閱使用 JavaScript 建立您的第一個 Windows 執行階段應用程式

指示

使用空白應用程式範本建立新專案

本文使用 Microsoft Visual Studio 2013 中基本的 [空白應用程式] 範本。若要建立新的 [空白應用程式],請執行下列動作:

  1. 啟動 Microsoft Visual Studio Express 2013 for Windows。

  2. 在 [起始頁] 索引標籤,按一下 [新增專案]。隨即開啟 [新增專案] 對話方塊。

  3. 在 [已安裝的] 窗格中,依序展開 [範本]、[JavaScript] 和 [市集應用程式]。選取您要建立的專案類別 ([Windows]、[Windows Phone] 或 [通用])。適用於 JavaScript 的可用專案範本會顯示在對話方塊的中央窗格中。

  4. 在中央窗格中,挑選 [空白應用程式] 專案範本。

  5. 在 [名稱] 文字方塊中,輸入排程器示範
  6. 按一下 [確定] 來建立專案。

新增適用於應用程式的 HTML 和 CSS

本文提供的範例應用程式使用以格線配置的簡單 HTML 介面,其中包含兩列和兩欄。若要設定頁面的 HTML 標記及用來設定應用程式樣式的階層式樣式表 (CSS),請執行下列動作:

  1. 開啟 default.html,在 <body> 元素內插入下列 HTML。這個程式碼應該是 <body> 元素的直屬子系。HTML 會建立三個 <div> 元素,可用於顯示來自 JavaScript 程式碼的輸出。

    
    <div id="scheduler">
        <button id="getState">Get scheduler state</button><br />
    </div>
    <div id="counter">
        <h2>Counter</h2>
        <div id="counterOutput"></div>
    </div>
    <div id="state">
        <h2>Scheduler state</h2>
        <textarea id="stateResult"></textarea>
    </div>
    
    
  2. 開啟 default.css 檔案 (css/default.css),並以下列程式碼取代內容。這個 CSS 會在應用程式中以簡單的 2 × 2 格線來排列 HTML。

    
    body {
        display: -ms-grid;
        -ms-grid-columns: 500px 1fr;
        -ms-grid-rows: 500px 1fr
    }
    body * {
        margin: 20px;
    }
    
    #scheduler {
        -ms-grid-column: 1;
        -ms-grid-row: 1
    }
    
    #state {
        -ms-grid-column: 2;
        -ms-grid-row: 2;
    }
    
    #state textarea {
        width: 400px;
        height: 200px;
    }
    
    #counter {
        -ms-grid-column: 1;
        -ms-grid-row: 2;
    }
    
    #counter div {
        font-size: 20pt;
        color: aqua;
    }
    
    

新增程式碼以在排程器上排程工作

適用於 JavaScript 的 Windows Library (WinJS) 中的 Scheduler 物件會使用單一通用佇列搭配以優先順序為基礎的排程原則。這可讓您指定工作的不同優先順序層級。接著工作會比對系統中的其他工具來排列優先順序。

使用 Scheduler.schedule 方法,您可以在排程器上將工作排入佇列。schedule 方法接受四個參數:workprioritythisArgname

  • work 參數接受定義要完成之工作的函式。呼叫該函式時,會傳遞單一引數—即 IJobInfo 物件。IJobInfo 物件包含可用來管理工作執行的成員。shouldYield 屬性指定是否應針對其他優先順序較高的工作暫停該工作。setWork 方法可讓工作一起合作獲利。它可以將工作重新排定在排程器覺得正確的未來時間完成,且不會讓工作遺失目前的優先順序層級。IJobInfo 物件也會包含 job 屬性,這個屬性會傳回 IJob 物件,其中包含有關工作本身的詳細資訊。
  • priority 參數,顧名思義,會設定工作的優先順序。它接受來自 Priority 列舉的值。例如,high 優先順序的工作會在 normal 優先順序的工作之前執行,後者會在優先順序 belowNormal 的工作之前執行 (依此類推)。
  • 您可以使用 schedule 方法的 thisArg 參數,指定要執行工作的內容。當工作執行時,為 work 參數傳遞的函式可以透過 this 關鍵字存取內容。
  • 第四個參數 name 提供在排程器佇列內識別工作的方法。這個參數讓您能夠在偵錯或記錄事件時,識別排程器上執行的工作。

在下一個程序中,您要建立在排程器上執行的工作。這個程式碼會排程從 1 數到 100,000 的低優先順序工作,當它在計數時便會更新使用者介面。計數器變數 (包含於父項語彙範圍) 維持工作的狀態。當優先順序較高的工作進入佇列時,這個工作就會結束,並在排程器上重新排程它的工作。

  1. 開啟 default.js,然後將下列程式碼新增到 app.onactivated 事件的處理常式中 (在 args.setPromise 的呼叫之後)。

    
    
    var scheduler = WinJS.Utilities.Scheduler;
    
    // Define a low-priority, time-consuming, job for the scheduler
    // to execute. This job counts from 1 to 100K, displaying each
    // number that it counts.
    var counter = 0;
    var counting = function (jobInfo) {
    
        while (counter < Math.pow(10, 5)) {
    
            counter++;
            counterOutput.innerText = counter;
    
            // Force the job to pause if a higher priority job
            // comes into the queue, and resume the job after
            // the other job is complete. Note that you need to 
            // include the 'break' to exit the while block.
            if (jobInfo.shouldYield) {
                jobInfo.setWork(counting);
                break;
            }    
        }
    }
    
    // Schedule the counting job at a low-level priority.
    scheduler.schedule(counting, 
        scheduler.Priority.idle, 
        null,
        "counting")
    
    
  2. 將下列程式碼新增到適用於 app.onactivated 的事件處理常式中,在您先前新增的程式碼下方。這個程式碼會將事件處理常式新增到 HTML 中宣告之按鈕的 click 事件中。該事件處理常式會在排程器中排程名為 gettingState 且優先順序為 normal 的新工作。由於 counting 工作含有 idle 的優先順序,因此,gettingState 工作會因為具有 normal 優先順序而優先執行。

    
    // Get the state of the scheduler. While the counting job
    // is running, this will display two jobs: this 'getting state'
    // job and the 'counting' job.
    var gettingState = function (jobInfo) {
        var currentTime = new Date();
        currentTime = currentTime.toLocaleTimeString();
    
        var state = scheduler.retrieveState();
        stateResult.value = currentTime + "\n\n" + state;
    }
    
    // When the button is clicked, display the current state of 
    // the scheduler to the user. This is scheduled as a 
    // normal-priority job so that the 'counting' job will yield to it.
    getState.addEventListener("click", function () { 
    
        scheduler.schedule( 
            gettingState, 
            scheduler.Priority.normal, 
            null, 
            "getting state");
                    
    });
    
    
  3. 按 F5 以執行範例,並在計數器執行時,按一下 [取得排程器狀態] 按鈕。在 [排程器狀態] 下方的輸出看起來與下列類似:

    9:11:52PM
    
    Jobs:
      *id: 3, priority: normal, name: getting state
       id: 2, priority: idle, name: counting
    Drain requests:
       None
    

    輸出顯示目前在該排程器佇列中的工作。星號指出目前正在排程器上執行的工作。

您也可以使用 Scheduler.execHigh 方法,較排程器上的所有其他工作優先執行。 execHigh 方法會在高優先順序層級同步執行一些程式碼 (傳回 execHigh 時完成)。這可確保在該執行期間開始的任何非同步作業都有高優先順序。

下列程序會變更 gettingState 工作,因此使用 execHigh 方法進行排程。

  1. 使用下列程式碼,取代 getState 按鈕的 click 事件處理常式。

    
    // When the button is clicked, display the current state of 
    // the scheduler to the user. This is scheduled with the highest
    // priority, so the counting job yields to it.
    getState.addEventListener("click", function () {
    
        scheduler.execHigh(gettingState);
    
    });
    
    
  2. 按 F5 以執行範例,並在計數器執行時,按一下 [取得排程器狀態] 按鈕。在 [排程器狀態] 下方的輸出現在看起來與下列類似:

    9:32:49PM
    
    Jobs:
       id: 2, priority: idle, name: counting
    Drain requests:
       None
    

    您會再次看見 gettingState 工作較 counting 工作優先執行。但在這個情況下,gettingState 不會在佇列中顯示,因為它會立即執行。

這裡提供 default.js 的完整程式碼。



(function () {
    "use strict";

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    var scheduler = WinJS.Utilities.Scheduler;

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());

            // Define a low-priority, time-consuming, job for the scheduler
            // to execute. This job counts from 1 to 100K, displaying each
            // number that it counts.
            var counter = 0;
            var counting = function (jobInfo) {

                while (counter < Math.pow(10, 5)) {

                    counter++;
                    counterOutput.innerText = counter;

                    // Force the job to pause if a higher priority job
                    // comes into the queue, and resume the job after
                    // the other job is complete. Note that you need to 
                    // include the 'break' to exit the while block.
                    if (jobInfo.shouldYield) {
                        jobInfo.setWork(counting);
                        break;
                    }    
                }
            }

            // Schedule the counting job at a low-level priority.
            scheduler.schedule(counting, 
                scheduler.Priority.idle, 
                null,
                "counting")

            // Get the state of the scheduler. While the counting job
            // is running, this will display two jobs: this 'getting state'
            // job and the 'counting' job.
            var gettingState = function (jobInfo) {
                var currentTime = new Date();
                currentTime = currentTime.toLocaleTimeString();

                var state = scheduler.retrieveState();
                stateResult.value = currentTime + "\n\n" + state;
            }

            // When the button is clicked, display the current state of 
            // the scheduler to the user. This is scheduled as a 
            // normal-priority job so that the 'counting' job will yield to it.
            getState.addEventListener("click", function () {

                // Uncomment the following line of code to run the gettingState
										    		// job at a 'normal' priority.
                //scheduler.schedule(gettingState,scheduler.Priority.normal, null, "getting state");
                scheduler.execHigh(gettingState);

            });
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();
})();


摘要與後續步驟

在這個快速入門中,您已了解如何排程簡單工作,也看到排程器如何針對優先順序較高的工作優先執行工作。

查看 gettingState 工作的輸出時,您可能會注意到 Drain requests 字串。排程器會清空佇列中所有高優先順序的工作—也就是說,它可以在 Scheduler 的通用佇列中執行所有工作。使用這個方法時,會犧牲回應性來增加輸送量。最好謹慎使用這個方法,而且只在回應性並不重要的情況下使用 (例如,在應用程式啟動期間)。 如需詳細資訊,請參閱 Scheduler.requestDrain 方法。

這個快速入門不會討論如何取得或執行排程器上的 Promise,或是如何使用擁有者權杖。如需這些主題的詳細資訊,請參閱 Scheduler 物件參考主題。

HTML 排程器範例

相關主題

JavaScript Web 工作者範例

 

 

顯示:
© 2015 Microsoft