nodejs 回調地獄解決 promise async


nodejs毀掉地獄是一直被人詬病的,以下總結一下解決毀掉地獄的一些方法。(暫時研究的比較淺)

1.promise

promise模式在任何時刻都處於以下三種狀態之一:未完成(unfulfilled)、已完成(resolved)和拒絕(rejected)。以CommonJS Promise/A 標准為例,promise對象上的then方法負責添加針對已完成和拒絕狀態下的處理函數。then方法會返回另一個promise對象,以便於形成promise管道,這種返回promise對象的方式能夠支持開發人員把異步操作串聯起來,如then(resolvedHandler, rejectedHandler); 。resolvedHandler 回調函數在promise對象進入完成狀態時會觸發,並傳遞結果;rejectedHandler函數會在拒絕狀態下調用。(其中rejectedHandler可選)。

以下為一個有幾級嵌套的函數,看起來比較令人惡心。(如果換成縮進四個字符可想而知)

'use strict';
const md = require('markdown-it')();
const fs = require('fs');
fs.watchFile('nodejs.md', (curr, prev) => {
  let mdStr = fs.readFile('./nodejs.md', 'utf-8', (err, data) => {
    let mdData = md.render(data);
    let htmlTemplate = fs.readFile('./index.html', 'utf-8', (err, data) => {
      let html = data.replace('{{content}}', mdData);
      console.log(mdData);
      fs.writeFile('./nodejs.html', html, 'utf-8', (err, data) => {
        if (err) {
          throw err;
        } else {
          console.log('OK');
        }
      });
    });
  });
});

一下用promise的方式實現同樣的效果,首先把異步函數封裝一下,然后下面可以指教調用。可能看起來代碼比之前的版本更多,但是封裝的異步函數是可以復用的。等任務多了就不顯得代碼多了。(但看最后調用函數的部分是不是優雅了不少)

'use strict';
const fs = require('fs');
const md = require('markdown-it')();
var Q = require('q');

function fs_readFile(file, encoding) {

  var deferred = Q.defer();
  fs.readFile(file, encoding, function(err, data) {
    if (err) deferred.reject(err); // rejects the promise with `er` as the reason
    else
      deferred.resolve(data) // fulfills the promise with `data` as the value
  });
  return deferred.promise; // the promise is returned
}

function fs_writeFile(file, data, encoding) {
  var deferred = Q.defer();
  fs.writeFile(file, data, encoding, function(err, data) {
    if (err) deferred.reject(err); // rejects the promise with `er` as the reason
    else deferred.resolve(data); // fulfills the promise with `data` as the value
  });
  return deferred.promise ;// the promise is returned
    //return 1; // the promise is returned
}

function fs_watchFile(file, curr, prev) {
  var deferred = Q.defer();
  fs.watchFile(file, function(curr, prev) {
    if (!prev) deferred.reject(err); // rejects the promise with `er` as the reason
    else deferred.resolve(curr); // fulfills the promise with `data` as the value
  });
  return deferred.promise // the promise is returned
}

function markdowm_convert(file, encoding, mdData) {

  var convertData = md.render(mdData);
  console.log(convertData);
  var deferred = Q.defer();
  fs.readFile(file, encoding, function(err, data) {
    if (err) deferred.reject(err); // rejects the promise with `er` as the reason
    else {
      data = data.replace('{{content}}', convertData);
      deferred.resolve(data); // fulfills the promise with `data` as the value
    }
  })
  return deferred.promise; // the promise is returned
}




// ===============promise實現  =====================
fs_watchFile('nodejs.md')
  .then(function() {
    return fs_readFile('./nodejs.md', 'utf-8');
  })
  .then(function(mdData) {
    return markdowm_convert('./index.html', 'utf-8', mdData);
  })
  .then(function(data) {
    fs_writeFile('./nodejs.html', data, 'utf-8');
  });

 2.async

node的async包有多的數不清的方法我暫時只實驗了一個waterfall

waterfall瀑布流的意思和async中另一個函數series差不多都是按照順序執行,不同之處是waterfall每執行完一個函數都會產生一個值,然后把這個值給下一個函數用。

以下是嵌套了兩級的讀寫文件程序

fs.readFile('01.txt','utf-8',function(err,date){
  fs.writeFile('02.txt',date,'utf-8',function(err,date){
    console.log('復制完了');
  });
})

用async.waterfall 后代碼如下

 

async.waterfall([
  function(cb){
    fs.readFile('01.txt','utf-8',function(err,result){
      cb(err,result);
    });

  },function(result,cb){
    fs.writeFile('02.txt',result,'utf-8',function(err,result){
      cb(err,result);
    });
  }
  ],function(err,result){
 console.log('復制完了');
})

 另外最近學習了generator及node co庫的源碼分析。詳見這里

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM