最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳談nodejs異步編程

 更新時間:2014年12月04日 11:08:38   投稿:hebedich  
本文詳細(xì)介紹了node.js異步編程的分類以及異步編程存在的問題,非常的詳盡,非常細(xì)致,這里推薦給小伙伴。

目前需求中涉及到大量的異步操作,實際的頁面越來越傾向于單頁面應(yīng)用。以后可以會使用backbone、angular、knockout等框架,但是關(guān)于異步編程的問題是首先需要面對的問題。隨著node的興起,異步編程成為一個非常熱的話題。經(jīng)過一段時間的學(xué)習(xí)和實踐,對異步編程的一些細(xì)節(jié)進(jìn)行總結(jié)。

1.異步編程的分類

     解決異步問題方法大致包括:直接回調(diào)、pub/sub模式(事件模式)、異步庫控制庫(例如async、when)、promise、Generator等。
1.1 回調(diào)函數(shù)

      回調(diào)函數(shù)是常用的解決異步的方法,經(jīng)常接觸和使用到,易于理解,并且在庫或函數(shù)中非常容易實現(xiàn)。這種也是大家接使用異步編程經(jīng)常使用到的方法。

      但是回調(diào)函數(shù)的方式存在如下的問題:

     1. 可能形成萬惡的嵌套金字塔,代碼不易閱讀;

     2. 只能對應(yīng)一個回調(diào)函數(shù),在很多場景中成為一個限制。

1.2 pub/sub模式(事件)

     該模式也稱為事件模式,是回調(diào)函數(shù)的事件化,在jQuery等類庫中非常常見。

     事件發(fā)布訂閱者模式本身并無同步與異步調(diào)用的問題,但是在node中,emit調(diào)用多半是伴隨事件循環(huán)而異步觸發(fā)的。該模式常用來解耦業(yè)務(wù)邏輯,事件發(fā)布者無須關(guān)注注冊的回調(diào)函數(shù),也不用關(guān)注回調(diào)函數(shù)的個數(shù),數(shù)據(jù)通過消息的方式可以很靈活的傳遞。

     該模式的好處是:1. 便于理解;2. 不再局限于一個回調(diào)函數(shù)。

     不好的地方時:1. 需要借助類庫; 2.事件與回調(diào)函數(shù)的順序很重要

復(fù)制代碼 代碼如下:

var img = document.querySelect(#id);
img.addEventListener('load', function() {
  // 圖片加載完成
    ......
});
img.addEventListener('error', function() {
  // 出問題了
  ......
});

  上述代碼存在兩個問題:

      a. img實際已經(jīng)加載完成,此時才綁定load回調(diào)函數(shù),結(jié)果回調(diào)不會執(zhí)行,但依然希望執(zhí)行該對應(yīng)回調(diào)函數(shù)。

復(fù)制代碼 代碼如下:

var img = document.querySelect(#id);
function load() {
  ...
}
if(img.complete) {
  load();
} else {
  img.addEventListener('load', load);
}
img.addEventListener('error', function() {
  // 出問題了
  ......
});

   b. 無法很好處理存在異常

      結(jié)論:事件機(jī)制最適合處理同一個對象上反復(fù)發(fā)生的事情,不需要考慮當(dāng)綁定回調(diào)函數(shù)之前事件發(fā)生的情況。

1.3 異步控制庫

      目前的異步庫主要有Q、when.js、win.js、RSVP.js等。

      這些庫的特點是代碼是線性的,可以從上到下完成書寫,符合自然習(xí)慣。

      不好的地方也是風(fēng)格各異,不便于閱讀,增加學(xué)習(xí)成本。

1.4 Promise

     Promise翻譯成中文為承諾,個人理解是異步完成之后,就會給外部一個結(jié)果(成功或失?。?,并承諾結(jié)果不再發(fā)生改變。換句話就是Promise反應(yīng)了一個操作的最終返回結(jié)果值(A promise represents the eventual value returned from the single completion of an operation)。目前Promise已經(jīng)引入到ES6規(guī)范里面,Chrome、firefox等高級瀏覽器已經(jīng)在內(nèi)部實現(xiàn)了該原生方法,使用起來相當(dāng)方便。

     下面從如下幾個方面來解析Promise的特點:

    1.4.1 狀態(tài)

     包含三種狀態(tài):pending、fulfilled、rejected,三種狀態(tài)只能發(fā)生兩種轉(zhuǎn)換(從pending--->fulfilled、pending—>rejected),并且狀態(tài)的轉(zhuǎn)換僅能發(fā)生一次。

    1.4.2 then方法

    then方法用于指定異步事件完成之后的回調(diào)函數(shù)。

   這個方法可以說是Promise的靈魂方法,該方法讓Promise充滿了魔力。有如下幾個具體表現(xiàn):

    a) then方法返回Promise。這樣就實現(xiàn)了多個異步操作的串行操作。

     關(guān)于上圖中黃圈1的對value的處理是Promise里面較為復(fù)雜的一個地方,value的處理分為兩種情況:Promise對象、非Promise對象。

     當(dāng)value 不是Promise類型時,直接將value作為第二個Promise的resolve的參數(shù)值即可;當(dāng)為Promise類型時,promise2的狀態(tài)、參數(shù)完全由value決定,可以認(rèn)為promsie2完全是value的傀儡,promise2僅僅是連接不同異步的橋梁。

復(fù)制代碼 代碼如下:

Promise.prototype.then = function(onFulfilled, onRejected) {
    return new Promise(function(resolve, reject) {           //此處的Promise標(biāo)注為promise2
        handle({
            onFulfilled: onFulfilled,
            onRejected: onRejected,
            resolve: resolve,
            reject: reject
        })
    });
}
function handle(deferred) {
    var handleFn;
    if(state === 'fulfilled') {
        handleFn = deferred.onFulfilled;
    } else if(state === 'rejected') {
        handleFn = deferred.onRejected;
    }
    var ret = handleFn(value);
    deferred.resolve(ret);                           //注意,此時的resolve是promise2的resolve
}
function  resolve(val) {
    if(val && typeof val.then === 'function') {
        val.then(resolve);                           // if val為promise對象或類promise對象時,promise2的狀態(tài)完全由val決定
        return;
    }
    if(callback) {                                    // callback為指定的回調(diào)函數(shù)
        callback(val);
    }
}

  b)實現(xiàn)了多個不同異步庫之間的轉(zhuǎn)換。

    在異步中存在一個叫thenable的對象,就是指具有then方法的對象,只要一個對象對象具有then方法,就可以對其進(jìn)行轉(zhuǎn)換,例如:

復(fù)制代碼 代碼如下:

var deferred = $('aa.ajax');      // !!deferred.then  === true
var P = Promise.resolve(deferred);
p.then(......)

1.4.3 commonJS Promise/A規(guī)范

      目前關(guān)于Promise的規(guī)范存在Promise/A和Promise/A+規(guī)范,這說明關(guān)于Promise的實現(xiàn)是挺復(fù)雜的。

復(fù)制代碼 代碼如下:

then(fulfilledHandler, rejectedHandler, progressHandler)

1.4.4 注意事項

     一個Promise里面的回調(diào)函數(shù)是共享value的,在結(jié)果處理中value作為參數(shù)傳遞給相應(yīng)的回調(diào)函數(shù),如果value是對象,那就要小心不要輕易修改value的值。

復(fù)制代碼 代碼如下:

var p = Promise.resolve({x: 1});
p.then(function(val) {
    console.log('first callback: ' + val.x++);
});
p.then(function(val) {
    console.log('second callback: ' + val.x)
})
// first callback: 1
// second callback: 2

1.5 Generator

      上面所有的方法均是基于回調(diào)函數(shù)來完成異步操作的,無非是對回調(diào)函數(shù)進(jìn)行封裝而已。ES6里面提出了Generator,增加了解決異步操作的途徑,不再依據(jù)回調(diào)函數(shù)來完成。

      Generator最大的特點就是可以實現(xiàn)函數(shù)的暫停、重啟,這個特性非常有利于解決異步操作。將Generator的暫停與promise的異常處理結(jié)合起來,可以比較優(yōu)雅地解決異步編程問題。具體實現(xiàn)參考:Kyle Simpson

2. 異步編程存在的問題

      2.1 異常處理

        a) 異步事件包括兩個環(huán)節(jié):發(fā)出異步請求、結(jié)果處理,這兩個環(huán)節(jié)通過event loop來連接起來。那么try catch來進(jìn)行異常捕獲的時候就需要分來捕獲。

復(fù)制代碼 代碼如下:

try {
    asyncEvent(callback);
} catch(err) {
    ......
}

     上述代碼是無法捕獲callback里面的異常,只能獲取發(fā)出請求環(huán)節(jié)的異常。這樣就存在問題:假如請求的發(fā)出和請求的處理是兩個人完成的,那么在異常處理的時候就存在問題?

        b)promise實現(xiàn)異常的傳遞,這帶來一些好處,在實際項目中保證代碼不被阻塞。但是如果異步事件比較多的時候,不容易找出到底是那個異步事件產(chǎn)生了異常。

復(fù)制代碼 代碼如下:

// 場景描述: 在CRM里面展示價格的報警信息,其中包含競對的信息。但是獲取競對的信息時間比較長,后端為了避免慢查詢,就把一條記錄拆成兩塊分別獲取。
// 第一步:獲取價格報警信息,除了競對信息
function getPriceAlarmData() {
    return new Promise(function(resolve) {
        Y.io(url, {
            method: 'get',
            data: params,
            on: function() {
                success: function(id, data) {
                    resolve(alarmData);
                }
            }
        });
    });
}
// 得到報警信息后,在去獲取競對信息
getPriceAlarmData().then(function(data) {
    // 數(shù)據(jù)渲染,除了競對信息
    render(data);
    return new Promise(function(resolve) {
        Y.io(url, {
            method: 'get',
            data: {alarmList: data},
            on: function() {
                success: function(id, compData) {
                    resolve(compData);
                }
            }
        });
    });
})      //  獲取完所有數(shù)據(jù)后進(jìn)行競對信息的渲染
.then(function(data) {
    // 渲染競對信息
    render(data)
}, function(err) {
    // 異常處理
    console.log(err);
});

      可以把上述代碼轉(zhuǎn)換成如下:

復(fù)制代碼 代碼如下:

try{
    // 獲取除競對以外的報警信息
    var alarmData = alarmDataExceptCompare();
    render(alarmData);
    // 根據(jù)報警信息查詢競對信息
    var compareData = getCompareInfo(alarmData);
    render(compareData);
} catche(err) {
    console.log(err.message);
}

在上述例子中把異常處理放到最后進(jìn)行處理,這樣當(dāng)其中存在某個環(huán)節(jié)出現(xiàn)異常,我們無法準(zhǔn)確知道到底是哪個事件產(chǎn)生的。     

2.2 jQuery.Deferred 的問題

     jQuery中也實現(xiàn)了異步操作,但是在實現(xiàn)上不符合promise/A+規(guī)范,主要表現(xiàn)在以下幾個方面:

    a. 參數(shù)的個數(shù):標(biāo)準(zhǔn)的Promise只能接受一個參數(shù),而jQuery中則可以傳遞多個參數(shù)

復(fù)制代碼 代碼如下:

function asyncInJQuery() {
    var d = new $.Deferred();
    setTimeout(function() {
        d.resolve(1, 2);
    }, 100);
    return d.promise()
}
asyncInJQuery().then(function(val1, val2) {
    console.log('output: ', val1, val2);
});
// output: 1 2

 b. 結(jié)果處理中異常的處理  

復(fù)制代碼 代碼如下:

function asyncInPromise() {
      return new Promise(function(resolve) {
        setTimeout(function() {
          var jsonStr = '{"name": "mt}';
          resolve(jsonStr);
        }, 100);
      });
  }
  asyncInPromise().then(function(val) {
      var d = JSON.parse(val);
      console.log(d.name);
  }).then(null, function(err) {
    console.log('show error: ' + err.message);
  });
// show error: Unexpected end of input
function asyncInJQuery() {
    var d = new $.Deferred();
    setTimeout(function() {
        var jsonStr = '{"name": "mt}';
        d.resolve(jsonStr);
    }, 100);
    return d.promise()
}
asyncInJQuery().then(function(val) {
    var d = JSON.parse(val);
    console.log(d.name);
}).then(function(v) {
    console.log('success: ', v.name);
}, function(err){
    console.log('show error: ' + err.message);
});
//Uncaught SyntaxError: Unexpected end of input

     從中可以看出,Promise對回調(diào)函數(shù)進(jìn)行了結(jié)果處理,可以捕獲回調(diào)函數(shù)執(zhí)行過程中的異常,而jQuery.Deferred卻不可以。

相關(guān)文章

  • Node.js中的HTTP請求與響應(yīng)詳解

    Node.js中的HTTP請求與響應(yīng)詳解

    本文詳細(xì)講解了Node.js中的HTTP請求與響應(yīng),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • nodejs和php實現(xiàn)圖片訪問實時處理

    nodejs和php實現(xiàn)圖片訪問實時處理

    這篇文章主要為大家詳細(xì)介紹了nodejs和php分別實現(xiàn)圖片訪問實時處理,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Nodejs下用submit提交表單提示cannot post錯誤的解決方法

    Nodejs下用submit提交表單提示cannot post錯誤的解決方法

    這篇文章主要介紹了Nodejs下用submit提交表單提示cannot post錯誤的解決方法,非常不錯,具有參考借鑒價值,感興趣的朋友一起看看吧
    2016-11-11
  • nodejs?快速入門之事件循環(huán)

    nodejs?快速入門之事件循環(huán)

    這篇文章主要介紹了nodejs?快速入門之事件循環(huán)的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • NodeJS處理Express中異步錯誤

    NodeJS處理Express中異步錯誤

    本文主要闡述如何在 Express 中使用錯誤處理中間件(error-handling middleware)來高效處理異步錯誤。在 Github 上有對應(yīng) 代碼實例 可供參考。
    2017-03-03
  • 詳解axios在node.js中的post使用

    詳解axios在node.js中的post使用

    最近因為工作的原因在學(xué)習(xí)使用網(wǎng)絡(luò)請求庫,因為這個項目用的是Promise,所以就選擇了axios,下面這篇文章主要給大家介紹了關(guān)于axios在node.js中的post使用的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-04-04
  • 淺談node中的cluster集群

    淺談node中的cluster集群

    這篇文章主要介紹了淺談node中的cluster集群,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • 使用Node.js創(chuàng)建HTTP服務(wù)器并實現(xiàn)公網(wǎng)訪問本地Server的步驟

    使用Node.js創(chuàng)建HTTP服務(wù)器并實現(xiàn)公網(wǎng)訪問本地Server的步驟

    Node.js含有一系列內(nèi)置模塊,使得程序可以脫離 Apache HTTP Server 或 IIS,作為獨(dú)立服務(wù)器運(yùn),下面將介紹如何簡單幾步實現(xiàn)遠(yuǎn)程公共網(wǎng)絡(luò)下訪問windwos node.js的服務(wù)端,感興趣的朋友一起看看吧
    2023-11-11
  • 搞懂什么是Node.js原來這么簡單

    搞懂什么是Node.js原來這么簡單

    這篇文章主要介紹了Node.js的概念和基本原理,對Node.js感興趣的同學(xué),一定要看一下
    2021-04-04
  • Node異步和事件循環(huán)的深入講解

    Node異步和事件循環(huán)的深入講解

    異步對于前端來說是老生常談的話題,同樣學(xué)習(xí)node也離不開異步IO與事件循環(huán),下面這篇文章主要給大家介紹了關(guān)于Node異步和事件循環(huán)的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07

最新評論

尼木县| 长岭县| 阳新县| 达尔| 会昌县| 兴山县| 鹤峰县| 萨嘎县| 满城县| 洛隆县| 称多县| 象州县| 揭阳市| 瑞金市| 沁阳市| 五寨县| 谢通门县| 大化| 贵定县| 台山市| 柘荣县| 峡江县| 阜新| 临清市| 凉城县| 贵州省| 鱼台县| 巨鹿县| 华坪县| 青冈县| 平罗县| 淄博市| 军事| 兴仁县| 迁安市| 丹棱县| 循化| 壤塘县| 屯门区| 南漳县| 兴文县|