黑馬Nodejs筆記03 Promise

回調地獄的產生

無法保證順序的代碼:

var fs = require('fs')
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
  if (err) {
    // return console.log('讀取失敗')
    // 拋出異常
    //    1. 阻止程序的執行
    //    2. 把錯誤消息打印到控制檯
     throw err
  	}
  	console.log(data)
})

fs.readFile('./data/b.txt', 'utf8', function (err, data) {
    if (err) {
      throw err
    }
    console.log(data)
})
            
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
      if (err) {
        throw err
      }
      console.log(data)
})

由於是readFile是異步的,無法保證讀取文件內容的輸出是一步一步來的

如何保證順序呢?通過回調的方式保證其順序

var fs = require('fs')

fs.readFile('./data/a.txt', 'utf8', function (err, data) {
  if (err) {
    throw err
  }
  console.log(data)
  fs.readFile('./data/b.txt', 'utf8', function (err, data) {
    if (err) {
      throw err
    }
    console.log(data)
    fs.readFile('./data/c.txt', 'utf8', function (err, data) {
      if (err) {
        throw err
      }
      console.log(data)
    })
  })
})

這裏只有三個異步函數,如果多個,會產生回調地獄。

一個任務依賴於一個異步任務執行完之後,這裏必須進行嵌套才能解決。

問題:嵌套的太深,代碼不好看,很難維護

怎麼去解決這個問題呢?在ES6中新增了一個API——Promise

Promise是如何解決回調地獄的

promise是一個容器,裏面存放了一個正在執行的任務(pending:正在執行),這個任務執行結束後,可能有兩個狀態,resolved(完成)和 rejected(失敗),狀態只能是其中的一種

promoise的使用

promise是一個構造函數

//promise容器一旦創建,就開始執行裏面的代碼,容器裏可以放置異步函數,但是promise本身不是異步的

//創建Promise容器,給別人一個承若:I Promise you
var p1 =  new Promise(function(resolve,reject){
    console.log('hello') //這裏的代碼不是異步的
    fs.readFile('./data/a.txt','utf8',function(err,data){
        if(err){
            //承渃容器中的任務失敗了,把容器的Pending狀態變爲 Rejected
        	//調用reject就相當於調用了then方法的第二個參數
            reject(err)
        }else{
            //承渃容器中的任務成功了,把容器的Pending狀態變爲 Resolved
            //調用resolve就相當於調用了then方法的第一個參數
            resolve(data)
        }
    })
})

//p1就是那個承若,當p1成功了,然後then做指定的操作,then方法接收的第一個function就是容器中的resolved函數
p1
  .then(function(data){
    console.log(data)
},function(err){
    console.log('讀取文件失敗了',err)
})

promise解決回調地獄問題示例

var p1 =  new Promise(function(resolve,reject){
    fs.readFile('./data/a.txt','utf8',function(err,data){
        if(err){
            reject(err)
        }else{
            resolve(data)
        }
    })
})

var p2 =  new Promise(function(resolve,reject){
    fs.readFile('./data/b.txt','utf8',function(err,data){
        if(err){
            reject(err)
        }else{
            resolve(data)
        }
    })
})

var p2 =  new Promise(function(resolve,reject){
    fs.readFile('./data/c.txt','utf8',function(err,data){
        if(err){
            reject(err)
        }else{
            resolve(data)
        }
    })
})

p1
  .then(function (data) {
    console.log(data)
    //當p1讀取成功的時候
    //當前函數中的return的結果就可以在後面的then中function
    //當你return 123 後面接接收到 123
    //	  return 'hello' 後面就接收到 ’hello'
    //	  沒有return後面收到的就是undefined
    //上面那些return的數據沒什麼卵用
    //真正有用的是:我們可以return一個promise對象
    //當return一個Promise對象的時候,後續的then中的方法的第一個參數會作爲p2的resolve
    return p2
  }, function (err) {
    console.log('讀取文件失敗了', err)
  })
  .then(function (data) {
    console.log(data)
    return p3
  })
  .then(function (data) {
    console.log(data)
    console.log('end')
  })

封裝promise ——API

var fs = require('fs')

function pReadFile(filePath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filePath, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

pReadFile('./data/a.txt')
  .then(function (data) {
    console.log(data)
    return pReadFile('./data/b.txt')
  })
  .then(function (data) {
    console.log(data)
    return pReadFile('./data/c.txt')
  })
  .then(function (data) {
    console.log(data)
  })

簡單封裝Promise版本的ajax方法

function pGet(url){
    return new Promise(function(resolve,reject){
        var xhr = new XMLHttpRequest()
        xhr.onLoad = function(){
            resolve(xhr.responseText)
        }
        xhr.onerror = function(err){
            reject(err)
        }
        xhr.open('get',url,true)
        xhr.send()
    })
}

pGet('http:127.0.0.1/user')
	.then(function(data){
    	console.log(data)
    return pGet('http://127.0.0.1/job')
	})
	.then(function(data){
		console.log(data)          
	})

Moogoose裏所有的封裝的函數都可以使用promise

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章