Promise的基礎(chǔ)用法

一溯祸、Promise的起因

當(dāng)項(xiàng)目有需求時叹俏,需要封裝一個方法,給一個要讀取文件的路徑嚷往,使用這個方法去讀取文件并把內(nèi)容返回葛账。
例:在一個file文件夾里有三個文檔,需要將里面內(nèi)容讀取出來

文件結(jié)構(gòu)

分別在1皮仁,2籍琳,3文件里保存111,222贷祈,333趋急,然后創(chuàng)建js文件

1.普通讀取文件的方式

const fs = require('fs')
const path = require('path')

fs.readFile(path.join(__dirname, './files/1.txt'), 'utf-8', (err, dataStr) => {
    if (err) throw err
    console.log(dataStr)   //111
})

結(jié)果輸出111


普通讀取文件結(jié)果

2.利用異步方式讀取文件

a.利用return

function getFileByPath(fpath, callback) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {
      if (err) throw(err)
      return dataStr
    })
}

var result = getFileByPath(path.join(__dirname, './files/1.txt'))
console.log(result)  //undefined

結(jié)果如下:


結(jié)果

原因:此時return沒有在主函數(shù)內(nèi)部,一個方法沒有return势誊,這個方法默認(rèn)返回undefined

b.利用callback

function getFileByPath(fpath, callback) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {
      if (err) throw(err)
      callback(dataStr)
    })
}

getFileByPath(path.join(__dirname, './files/1.txt'), (err, dataStr) => {
     console.log('callback調(diào)用的方法-----'+dataStr)
  })

結(jié)果輸出為:


callback方法調(diào)用函數(shù)結(jié)果輸出
A.callback對異常結(jié)果的處理

我們可以規(guī)定: callback 中呜达,有兩個參數(shù);第一個參數(shù)粟耻,是 失敗的結(jié)果查近;第二個參數(shù)是成功的結(jié)果;
如果成功了挤忙,返回的結(jié)果霜威,應(yīng)該位于 callback 參數(shù)的第二個位置,此時册烈, 第一個位置 由于沒有出錯戈泼,所以,放一個 null;
如果失敗了矮冬,則 第一個位置放 Error對象谈宛,第二個位置放置一個 undefined

function getFileByPath(fpath, callback) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {
      if (err) return callback(err)
      callback(null, dataStr)
    })
}
getFileByPath(path.join(__dirname, './files/1.txt'), (err, dataStr) => {
    if (err) return console.log(err.message)
    console.log(dataStr)//111
  })

結(jié)果輸出111
若路徑錯誤的話,結(jié)果輸出

ENOENT: no such file or directory, open

B.定義兩個callback將正確的路徑和錯誤的路徑分開
const fs = require('fs')
const path = require('path')

//定義兩個callback將正確的路徑和錯誤的路徑分開
function getFileByPath(fpath, succCb, errCb) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err) return errCb(err)
    succCb(dataStr)
  })
}

 getFileByPath(path.join(__dirname, './files/1.txt'), function (data) {
    console.log(data + '成功了Lナ稹_郝肌!')
 }, function (err) {
   console.log('失敗的結(jié)果琼牧,我們使用失敗的回調(diào)處理了一下:' + err.message)
 })

當(dāng)路徑正確時:


路徑正確

當(dāng)路徑錯誤時:


路徑錯誤時
C.當(dāng)出現(xiàn)需求時:先讀取文件1恢筝,再讀取文件2,最后再讀取文件3
const fs = require('fs')
const path = require('path')

function getFileByPath(fpath, succCb, errCb) {
  fs.readFile(fpath, 'utf-8', (err, dataStr) => {
    if (err) return errCb(err)
    succCb(dataStr)
  })
}
getFileByPath(path.join(__dirname, './files/1.txt'), function (data) {
    console.log(data)
  
    getFileByPath(path.join(__dirname, './files/2.txt'), function (data) {
      console.log(data)
  
      getFileByPath(path.join(__dirname, './files/3.txt'), function (data) {
        console.log(data)
      })
    })
})

結(jié)果如下:


回調(diào)結(jié)果

當(dāng)出現(xiàn)回調(diào)地獄時巨坊,可以利用ES6的promise來解決

二撬槽、promise的基本介紹

本質(zhì):是單純的為了解決回調(diào)地獄問題;并不能幫我們減少代碼量趾撵;
將回調(diào)地獄的調(diào)用關(guān)系侄柔,改變?yōu)榇?lián)關(guān)系
1. Promise 是一個 構(gòu)造函數(shù),既然是構(gòu)造函數(shù)占调, 那么暂题,我們就可以 new Promise() 得到一個 Promise 的實(shí)例;
2. 在 Promise 上究珊,有兩個函數(shù)薪者,分別叫做 resolve(成功之后的回調(diào)函數(shù)) 和 reject(失敗之后的回調(diào)函數(shù))
3.在 Promise 構(gòu)造函數(shù)的 Prototype 屬性上,有一個 .then() 方法剿涮,也就說言津,只要是 Promise 構(gòu)造函數(shù)創(chuàng)建的實(shí)例,都可以訪問到 .then() 方法
4. Promise 表示一個 異步操作取试;每當(dāng)我們 new 一個 Promise 的實(shí)例悬槽,這個實(shí)例,就表示一個具體的異步操作瞬浓;
5.既然 Promise 創(chuàng)建的實(shí)例陷谱,是一個異步操作,那么瑟蜈,這個 異步操作的結(jié)果,只能有兩種狀態(tài):
- 5.1 狀態(tài)1: 異步執(zhí)行成功了渣窜,需要在內(nèi)部調(diào)用 成功的回調(diào)函數(shù) resolve 把結(jié)果返回給調(diào)用者铺根;
- 5.2 狀態(tài)2: 異步執(zhí)行失敗了,需要在內(nèi)部調(diào)用 失敗的回調(diào)函數(shù) reject 把結(jié)果返回給調(diào)用者乔宿;
- 5.3 由于 Promise 的實(shí)例位迂,是一個異步操作,所以,內(nèi)部拿到 操作的結(jié)果后掂林,無法使用 return 把操作的結(jié)果返回給調(diào)用者臣缀; 這時候,只能使用回調(diào)函數(shù)的形式泻帮,來把 成功 或 失敗的結(jié)果精置,返回給調(diào)用者;
6. 我們可以在 new 出來的 Promise 實(shí)例上锣杂,調(diào)用 .then() 方法脂倦,【預(yù)先】 為 這個 Promise 異步操作,指定 成功(resolve) 和 失斣(reject) 回調(diào)函數(shù)赖阻;

1.形式上和具體的promise異步操作的區(qū)別

注意:這里 new 出來的 promise, 只是代表 【形式上】的一個異步操作踱蠢;
什么是形式上的異步操作:就是說火欧,我們只知道它是一個異步操作,但是做什么具體的異步事情茎截,目前還不清楚

// 這是一個具體的異步操作苇侵,其中,使用 function 指定一個具體的異步操作
var promise = new Promise(function(){
  // 這個 function 內(nèi)部寫的就是具體的異步操作<诨ⅰP铺础!
}) 

2.創(chuàng)建一個具體的異步操作

const fs = require('fs')
var promise = new Promise(function () {
    fs.readFile('./files/2.txt', 'utf-8', (err, dataStr) => {
      if (err) throw err
      console.log(dataStr)  //222
    })
}) 

注意:每當(dāng) new 一個 Promise 實(shí)例的時候霎俩,就會立即執(zhí)行這個異步操作中的代碼哀军;即,當(dāng)前操作會立即執(zhí)行
也就是說打却,new 的時候杉适,除了能夠得到 一個 promise 實(shí)例之外,還會立即調(diào)用 我們?yōu)?Promise 構(gòu)造函數(shù)傳遞的那個 function柳击,執(zhí)行這個 function 中的 異步操作代碼猿推;

3.利用函數(shù)封裝,之后再進(jìn)行調(diào)用

使promise不用立即執(zhí)行

function getFileByPath(fpath) {
    var promise = new Promise(function () {
      fs.readFile(fpath, 'utf-8', (err, dataStr) => {
  
        if (err) throw err
        console.log(dataStr)
  
      })
    })
}
getFileByPath('./files/2.txt')  //222

三捌肴、通過.then指定成功或失敗的回調(diào)

function getFileByPath(fpath) {
    return new Promise(function (resolve, reject) {
      fs.readFile(fpath, 'utf-8', (err, dataStr) => {
  
        if (err) return reject(err)
        resolve(dataStr)
  
      })
    })
  }
  
   getFileByPath('./files/2.txt')
    .then(function (data) {
      console.log(data) //222
    }, function (err) {
      console.log(err.message)
    }) 

不管是成功還是失敗都會返回讀取到的內(nèi)容

1.解決回調(diào)地獄

需求:先讀取文件1蹬叭,在讀取2,最后讀取3
注意:通過 .then 指定 回調(diào)函數(shù)的時候状知,成功的回調(diào)函數(shù)秽五,必須傳,但是饥悴,失敗的回調(diào)坦喘,可以省略不傳

const fs = require('fs')

function getFileByPath(fpath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {

      if (err) return reject(err)
      resolve(dataStr)

    })
  })
}
//錯誤示范
getFileByPath('./files/1.txt')
  .then(function (data) {
    console.log(data)

    getFileByPath('./files/2.txt')
      .then(function (data) {
        console.log(data)

        getFileByPath('./files/3.txt')
          .then(function (data) {
            console.log(data)
          })
      })
  })

這是一個錯誤示范

正確做法:

在上一個 .then 中盲再,返回一個新的 promise 實(shí)例,可以繼續(xù)用下一個 .then 來處理

const fs = require('fs')

function getFileByPath(fpath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {

      if (err) return reject(err)
      resolve(dataStr)

    })
  })
}
//正確做法
getFileByPath('./files/1.txt')
.then(function (data) {
  console.log(data)

  // 讀取文件2
  return getFileByPath('./files/2.txt')
})
.then(function (data) {
  console.log(data)

  return getFileByPath('./files/3.txt')
})
.then(function (data) {
  console.log(data)
})

結(jié)果如下:


.then調(diào)用結(jié)果如下

四瓣铣、捕獲異常的兩種方式

1.如果前面的 Promise 執(zhí)行失敗答朋,我們不想讓后續(xù)的Promise 操作被終止,可以為每個 promise 指定失敗的回調(diào)

如果前面的 Promise 執(zhí)行失敗了棠笑,但是不要影響后續(xù) promise 的正常執(zhí)行梦碗,此時,我們可以單獨(dú)為 每個 promise腐晾,通過 .then 指定一下失敗的回調(diào)

const fs = require('fs')

function getFileByPath(fpath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {

      if (err) return reject(err)
      resolve(dataStr)

    })
  })
}

getFileByPath('./files/11.txt')
  .then(function (data) {
    console.log(data)

    // 讀取文件2
    return getFileByPath('./files/2.txt')
  }, function (err) {
    console.log('這是失敗的結(jié)果:' + err.message)
    // return 一個 新的 Promise
    return getFileByPath('./files/2.txt')
  })
  .then(function (data) {
    console.log(data)

    return getFileByPath('./files/3.txt')
  })
  .then(function (data) {
    console.log(data)
  }).then(function (data) {
    console.log(data)
  }) 

 console.log('OKOKOK')

結(jié)果如下:


方式一

2.利用catch去處理promise拋出的異常

如果 后續(xù)的Promise 執(zhí)行叉弦,依賴于 前面 Promise 執(zhí)行的結(jié)果,如果前面的失敗了藻糖,則后面的就沒有繼續(xù)執(zhí)行下去的意義了淹冰,此時,我們想要實(shí)現(xiàn)巨柒,一旦有報(bào)錯樱拴,則立即終止所有 Promise的執(zhí)行;

const fs = require('fs')

function getFileByPath(fpath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {

      if (err) return reject(err)
      resolve(dataStr)

    })
  })
}
//catch處理異常
getFileByPath('./files/1.txt')
  .then(function (data) {
    console.log(data)

    // 讀取文件2
    return getFileByPath('./files/22.txt')
  })
  .then(function (data) {
    console.log(data)

    return getFileByPath('./files/3.txt')
  })
  .then(function (data) {
    console.log(data)
  })
  .catch(function (err) {     console.log('這是自己的處理方式:' + err.message)
  })

catch 的作用: 如果前面有任何的 Promise 執(zhí)行失敗洋满,則立即終止所有 promise 的執(zhí)行晶乔,并馬上進(jìn)入 catch 去處理 Promise中 拋出的異常;

五牺勾、JQuery中Ajax使用promise指定成功的回調(diào)函數(shù)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>

  <input type="button" value="獲取數(shù)據(jù)" id="btn">

  <script src="./node_modules/jquery/dist/jquery.min.js"></script>

  <script>
    $(function () {
      $('#btn').on('click', function () {
        $.ajax({
          url: './data.json',
          type: 'get',
          dataType: 'json'
        })
          .then(function (data) {
            console.log(data)
          })
      })
    });
  </script>
</body>

</html>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末正罢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子驻民,更是在濱河造成了極大的恐慌翻具,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件回还,死亡現(xiàn)場離奇詭異裆泳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)柠硕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門工禾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蝗柔,你說我怎么就攤上這事闻葵。” “怎么了癣丧?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵槽畔,是天一觀的道長。 經(jīng)常有香客問我坎缭,道長竟痰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任掏呼,我火速辦了婚禮坏快,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘憎夷。我一直安慰自己莽鸿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布拾给。 她就那樣靜靜地躺著祥得,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蒋得。 梳的紋絲不亂的頭發(fā)上级及,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音额衙,去河邊找鬼饮焦。 笑死,一個胖子當(dāng)著我的面吹牛窍侧,可吹牛的內(nèi)容都是我干的县踢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼伟件,長吁一口氣:“原來是場噩夢啊……” “哼硼啤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起斧账,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤谴返,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后其骄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亏镰,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年拯爽,在試婚紗的時候發(fā)現(xiàn)自己被綠了索抓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡毯炮,死狀恐怖逼肯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桃煎,我是刑警寧澤篮幢,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站为迈,受9級特大地震影響三椿,放射性物質(zhì)發(fā)生泄漏缺菌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一搜锰、第九天 我趴在偏房一處隱蔽的房頂上張望伴郁。 院中可真熱鬧,春花似錦蛋叼、人聲如沸焊傅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狐胎。三九已至,卻和暖如春歌馍,著一層夾襖步出監(jiān)牢的瞬間握巢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工骆姐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留镜粤,地道東北人。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓玻褪,卻偏偏與公主長得像肉渴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子带射,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容