<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                javascript在進行資源請求時,會使用**異步**的方法。這種聰明的方法能夠巧妙地規避請求資源帶來的延遲。但不太友好的是:我們并不能夠由代碼上直接判斷出哪個方法進行資源請求,哪個方法是異步的。 ## 同步與異步 我們平時接觸的大多數的代碼都是同步的,同步代碼有特性就是按書寫的順序依次執行。書寫在前的執行也在前,書寫在后的執行也在后;異步代碼同打破了同步這一常的執行思路。即:書寫在前的,不見得會執行在前;書寫在后的,也不見得執行在后。 ## 異步示例 比如我們剛剛請求的所有教師資源: ```typescript ngOnInit(): void { this.httpClient.get<[]>('assets/teacher-all.json') .subscribe(teachers => this.teachers = teachers); } ``` 上述代碼是一個標準的異步請求,我們簡單對上述代碼打幾個**點**: ```typescript ngOnInit(): void { console.log('1'); ? this.httpClient.get<[]>('assets/teacher-all.json') ? .subscribe(teachers => { console.log('2'); ? this.teachers = teachers; }); console.log('3'); ? } ``` 來到控制臺查看執行順序為????: ![](https://img.kancloud.cn/82/c5/82c5e2b9670d6e6a32ea8f5412811a98_554x217.png) 雖然?在書寫順序上在?之前,但在執行的順序卻在?之后。 從根本上講發生上述原因是由于`?httpClient.get`是個異步方法,當執行到此方法時javascript聰明地繼續往下執行?,而不是等待其請求完畢后執行?。這在真實的環境中是非常有必要的,如果沒有異步的存在,我們就必須**等待** ? 返回結果后再去執行 ?。而**等待**時間具有不確定性,可能等0.1秒就返回了結果,也可以等10秒,或是根本就等不到結果。在異步的作用下,我們可以忽略這個等待的過程,而僅在請求成功返回數據后再去接著執行提前書寫好的?。 ## 回調 由于**異步**的存在,我們無法(實際上是有辦法的)像使用同步方法一樣來獲取到資源請求的返回值: ```typescript ngOnInit(): void { console.log('1'); const teachers? = this.httpClient.get<[]>('assets/teacher-all.json') .subscribe(); console.log?(JSON.stringify(teachers, (key, value)?? => { if (['_subscriptions', 'destination'].indexOf(key) === -1) { return value; } })); console.log('3'); } ``` * ?? 請忽略此處的代碼,當前僅作演示,不需要大家掌握 比如我們在上述代碼中預使用同步的思想來獲取所有的教師數據,但實際上獲取的卻是: ![](https://img.kancloud.cn/d5/83/d58387283ba97cd00218e686062617a6_1080x210.png) 那么若要獲取這個**等待**一會才會出現的返回值,則需要使用同步的思想。 ### 數據與算法 劉宇軒的高分文章[從零起步,真正理解Javascript回調函數](https://segmentfault.com/a/1190000021942060)很好的對回調函數進行了總結,適合于新手閱讀。該文章中提到函數是由數據與算法組成的,我們普通的函數是固化算法,通過改變數據的方法來改變最終的結果: ```js /** * 平方算法 * @param 變化是參數a * @return 返回的是a的平方 */ var test = function (a) { return a * a; }; test(2); test(3); ``` ![](https://img.kancloud.cn/78/2e/782e03e572be4d89aed6d0bdfbcfa979_294x129.png) 而帶有回調函數的這種方法則是數據固定,改變是算法: ```js /** * 數據固定,根據傳入的算法來決定返回值 * @param 變化是算法 * @return 返回算法對2的處理結果 */ var test = function (callback) { return callback(2); }; // 平方算法 test(a => a * a); // 立方算法 test(a => a * a * a); ``` ![](https://img.kancloud.cn/99/d5/99d512cd457735cd618dfc58cc6bfc78_416x132.png) 普通的方法可從方法體內直接使用傳入的參數;特殊的方法由于接收到的參數類型為算法(函數),所以使用`xxx(參數1, 參數2, ...)`的方法來使用傳入的xxx參數。 其實當某個方法支持傳入算法時,該算法是否執行、什么時候執行、執行幾次、帶有什么參數執行,則完全由該方法說了算。 比如: ```js /** * 不執行傳入算法 * @param callback * @return 123 */ var test = function (callback) { return 123; }; // 平方算法 test(a => a * a); // 立方算法 test(a => a * a * a); ``` callback被執行0次:無論什么算法傳入test,均不會被執行,最終的結果都是123。 ```js /** * 執行2次傳入的算法 * @param callback * @return 2與3結過算法運算后相乘的結果 */ var test = function (callback) { return callback(2) * callback(3); }; // 平方算法 test(a => a * a); ``` callback被執行2次。 ![](https://img.kancloud.cn/31/ad/31ad471078543100c45c42d66e4baf47_298x108.png) 我們當然也可以在方法中使用for循環的方法來使callback執行多次。a 所以:callback是否被執行,何時被執行,以什么樣的參數被執行,執行多少次,全部取決于test方法是否在其方法體中調用callback,什么時候調用callback,調用時候傳了什么樣的參數,以及調用了多少次callback。 ## 異步與回調 異步與回調的結合,則很好的解決了**等待**一會再返回數據的問題。這是由于在方法調用傳入的算法的過程中,可以將方法中的值通過傳入算法參數的方式來傳遞給算法,比如: ```js var test = function (callback) { return callback(2?); }; ``` * ? 2作為參數傳遞給了callback。 而當callback接收到2時,便可以隨意利用該值了,當然也包括將其打印到控制臺,或是將其值賦予當前組件的任意屬性: ```js var subscribe = function (callback) { 發起資源請求 等待請求并向JS發送通知:當前請求為異步,請不要等待我執行完畢 if (請求成功) { callback(請求得到的數據?); } else { 什么也不做 } }; subscribe(teachers => this.teachers = teachers?); ``` * ? 將請求到的數據通過算法的參數傳遞出去 * ? 接收到數據后,將其賦予當前組件的teachers屬性 學到這,相信本節開篇的????執行順序也就不難理解了: ```typescript ngOnInit(): void { console.log('1'); ? this.httpClient.get<[]>('assets/teacher-all.json') ? .subscribe(teachers => { console.log('2'); ? this.teachers = teachers; }); console.log('3'); ? } ``` >[info] 在實際的開發中,回調函數更多的被用于異步傳值。 # 本節作業 請自定義一個test方法,當如下調用時,在打印臺中打印31,即:`2 * 2 + 3 * 3 * 3`; ```js test(a => a * a, b => b * b * b, c => console.log(c)); ``` ![](https://img.kancloud.cn/37/94/3794f3ac3a5d08ec179f11d957fc1592_528x115.png) 異步與回調是個新的重要知識點,如果你尚無法獨立完成本作業,請嘗試重新學習本小節內容。 >[success] 簡單的事情重復做你就是專家,重復的事情認真做你就是贏家! 再定義一個test方法,當如下調用時,仍在打印臺中打印17,即:`2 * 2 * 2 + 3 * 3`; ```js test(2, 3, a => a * a, b => b * b * b, c => console.log(c)); ``` ![](https://img.kancloud.cn/40/33/4033b033439cd7cb73d230e598cf13e8_718x120.png) # 本節資源 | 名稱 | 地址 | | ------------------------------------ | ------------------------------------------------------------ | | 從零起步,真正理解Javascript回調函數 | [https://segmentfault.com/a/1190000021942060](https://segmentfault.com/a/1190000021942060) |
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看