js中的異步與同步,解決由異步引發的問題

以前在項目中遇到過好屢次由於異步引發的變量沒有值,因此意識到了認識js中同步與異步機制的重要性node

在單線程的js中,異步代碼會被放入一個事件隊列,等到全部其餘代碼執行後再執行,而不會阻塞線程。ajax

下面是js幾種最多見的異步狀況:promise

  1. 異步函數 setTimeout和setInterval
    異步函數,如setTimeout和setInterval,被壓入了稱之爲Event Loop的隊列。
    setTimeout:在指定的毫秒數後,將定時任務處理的函數添加到執行隊列的隊尾。因此有時候也可使用setTimeout解決異步帶來的問題
    setInterval:按照指定的週期(以毫秒數計時),將定時任務處理函數添加到執行隊列的隊尾。

    Event Loop是一個回調函數隊列。當異步函數執行時,回調函數會被壓入這個隊列。JavaScript引擎直到異步函數執行完成後,纔會開始處理事件循環。這意味着JavaScript代碼不是多線程的,即便表現的行爲類似。事件循環是一個先進先出(FIFO)隊列,這說明回調是按照它們被加入隊列的順序執行的。
  2. ajax
  3. node.js中的許多函數也是異步的

解決由的js異步引發的問題辦法:ruby

  1. 命名函數
    清除嵌套回調的一個便捷的解決方案是簡單的避免雙層以上的嵌套。傳遞一個命名函數給做爲回調參數,而不是傳遞匿名函數
    例:
     1 var fromLatLng, toLatLng;
     2 var routeDone = function( e ){
     3     console.log( "ANNNND FINALLY here's the directions..." );
     4     // do something with e
     5 };
     6 var toAddressDone = function( results, status ) {
     7     if ( status == "OK" ) {
     8         toLatLng = results[0].geometry.location;
     9         map.getRoutes({
    10             origin: [ fromLatLng.lat(), fromLatLng.lng() ],
    11             destination: [ toLatLng.lat(), toLatLng.lng() ],
    12             travelMode: "driving",
    13             unitSystem: "imperial",
    14             callback: routeDone
    15         });
    16     }
    17 };
    18 var fromAddressDone = function( results, status ) {
    19     if ( status == "OK" ) {
    20         fromLatLng = results[0].geometry.location;
    21         GMaps.geocode({
    22             address: toAddress,
    23             callback: toAddressDone
    24         });
    25     }
    26 };
    27 GMaps.geocode({
    28     address: fromAddress,
    29     callback: fromAddressDone
    30 });

     async.js 庫能夠幫助咱們處理多重Ajax requests/responses,如:多線程

     1 async.parallel([
     2     function( done ) {
     3         GMaps.geocode({
     4             address: toAddress,
     5             callback: function( result ) {
     6                 done( null, result );
     7             }
     8         });
     9     },
    10     function( done ) {
    11         GMaps.geocode({
    12             address: fromAddress,
    13             callback: function( result ) {
    14                 done( null, result );
    15             }
    16         });
    17     }
    18 ], function( errors, results ) {
    19     getRoute( results[0], results[1] );
    20 });
  2. 使用promise
    promise在異步執行的流程中,把執行代碼和處理結果的代碼清晰地分離了:

    promise還能夠作若干個異步的任務,例:有一個異步任務,須要先作任務1,若是任務成功後再作任務2,任何任務失敗則再也不繼續並執行錯誤處理函數。
    job1.then(job2).then(job3).catch(handleError);  //job1job2job3都是Promise對象app

    例:
     1 'use strict';
     2 
     3 var logging = document.getElementById('test-promise2-log');
     4 while (logging.children.length > 1) {
     5     logging.removeChild(logging.children[logging.children.length - 1]);
     6 }
     7 
     8 function log(s) {
     9     var p = document.createElement('p');
    10     p.innerHTML = s;
    11     logging.appendChild(p);
    12 }
    13 // 0.5秒後返回input*input的計算結果:
    14 function multiply(input) {
    15     return new Promise(function (resolve, reject) {
    16         log('calculating ' + input + ' x ' + input + '...');
    17         setTimeout(resolve, 500, input * input);
    18     });
    19 }
    20 
    21 // 0.5秒後返回input+input的計算結果:
    22 function add(input) {
    23     return new Promise(function (resolve, reject) {
    24         log('calculating ' + input + ' + ' + input + '...');
    25         setTimeout(resolve, 500, input + input);
    26     });
    27 }
    28 
    29 var p = new Promise(function (resolve, reject) {
    30     log('start new Promise...');
    31     resolve(123);
    32 });
    33 
    34 p.then(multiply)
    35  .then(add)
    36  .then(multiply)
    37  .then(add)
    38  .then(function (result) {
    39     log('Got value: ' + result);
    40 });

    關於promise的兩個方法

    異步

     1 var p1 = new Promise(function (resolve, reject) {
     2     setTimeout(resolve, 500, 'P1');
     3 });
     4 var p2 = new Promise(function (resolve, reject) {
     5     setTimeout(resolve, 600, 'P2');
     6 });
     7 // 同時執行p1和p2,並在它們都完成後執行then:
     8 Promise.all([p1, p2]).then(function (results) {
     9     console.log(results); // 得到一個Array: ['P1', 'P2']
    10 });
    1 var p1 = new Promise(function (resolve, reject) {
    2     setTimeout(resolve, 500, 'P1');
    3 });
    4 var p2 = new Promise(function (resolve, reject) {
    5     setTimeout(resolve, 600, 'P2');
    6 });
    7 Promise.race([p1, p2]).then(function (result) {
    8     console.log(result); // 'P1'
    9 });
    //因爲執行較快,Promise的將得到結果。仍在繼續執行,但執行結果將被丟棄。p1then()'P1'p2

 

本文參考:async

http://blog.csdn.net/u013063153/article/details/52457307函數

https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/0014345008539155e93fc16046d4bb7854943814c4f9dc2000oop

相關文章
相關標籤/搜索