從入門到放棄之promise用法(上)

言sir發表於2018-06-14

參考文獻

一、promise的簡述

含義

  • Promise是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函式和事件——更合理和更強大。它由社群最早提出和實現,ES6將其寫進了語言標準,統一了用法,原生提供了Promise物件。
  • 所謂Promise,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說,Promise 是一個物件,從它可以獲取非同步操作的訊息。Promise 提供統一的 API,各種非同步操作都可以用同樣的方法進行處理。

簡單說promise就是一個承諾,未來才會實現。比如媳婦等我有錢了給你買包, 先等著,給你個承諾,等有錢了再買。承諾就是一個等待態,你可以設定成功或者失敗,即買包和不買包,這就是下面所說的三個狀態了。

特點

  • 物件的狀態不受外界影響。Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、resolves(已成功)和rejected(已失敗)。
  • 一旦狀態改變,就不會再變。只有兩種可能:從pending變為fulfilled和從pending變為rejected。

簡單說就是Promise物件有三種狀態,一旦成功就不能失敗,一旦失敗就不能成功

主要解決回撥地獄,函式巢狀的問題

  • 比如看我們下面的程式碼
let fs = require("fs");
fs.readFile("a.txt",'utf8',function(data1){ 
    fs.readFile("b.txt",'utf8',function(data2){ 
        console.log(data1,data2);
    })
})
複製程式碼

data2資料需要依賴上一次的返回結果data1時,就會造成巢狀問題,當無限巢狀下去,就會形成回撥地獄問題, 下面我們來看promise基礎用法,怎麼解決這類問題

二、promise的基礎用法

建立一個promise例項

  • Promise本身是一個建構函式,需要我們new 一個例項,傳遞一個函式作為引數(我們稱之為執行器函式 executor),函式接收兩個引數 resolve(成功函式) 、reject(失敗函式)
let p =new Promise((resolve,reject)=>{
    //執行器預設在new時就會被呼叫,立即執行 
    console.log("1")
    resolve("123") //成功函式resolve,傳遞了123
});
複製程式碼

這有什麼用呢,我們來看p的then方法怎麼得到123

then鏈式寫法

  • then中傳遞兩個函式,第一個函式對應成功時候回撥(即resolve('123')),第一個函式對應失敗時候回撥(即reject('123'))
  • 這樣的話就把resolve('123')中的123,被then中成功回撥所捕獲 data就是123啦,如果傳遞reject('123')就會被失敗回撥捕獲
p.then(value=>{ 
    //value指的上面resolve傳遞的引數,成功的原因
    console.log(value) 
},err=>{
    //失敗的原因, reject傳遞的引數
     console.log(err)
})
.then(value=>{
    console.log(value)
},err=>{
     console.log(err)
})
複製程式碼
  • 回想下我們如何用promise解決上述巢狀問題
let fs = require('fs');
function read(file){
    return new Promise(function(resolve,reject){
        fs.readFile(file,'utf8',function(err,data){
            if (err) {
                return reject(err);
            }
            resolve(data);
        })
    })
}
read('./a.txt').then(function(data){
    return read('./b.txt');
}).then(function(data){
    console.log(data);
})
複製程式碼
  • 上述的寫法是不是更具有流程感
  • then還可以穿透,什麼意思呢,直接上程式碼
let Promise = require('./Promise');
let promise = new Promise((resolve,reject)=>{
  resolve('hello');
});
promise.then().then().then(data=>{ //可以無限的then,但結果仍會拿到
  console.log(data); //'hello'
},err=>{
  console.log('err',err);
})

複製程式碼

錯誤處理catch

  • catch捕獲錯誤,與try/catch語句有類似的功能,可以把then第二個引數省去,在最後面寫上.catch
p.then().then().catch(err=>{
    console.log(err)
})
複製程式碼

Promise.all()

  • Proise.all()在所有的非同步操作執行完後才執行的回撥,接受一個陣列,陣列中每項都應是一個promise例項,Promise.all()返回的結果也是一個promise,因此也可以.then下去,上一段程式碼吧
let fs = require("fs");
function read(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, 'utf8', function(err, data) {
      if (err) return reject(err);
      resolve(data);
    });
  });
}
Promise.all([read("1.txt"), read("2.txt")]).then( //可以then說明Promise.all()返回結果也是promise
  data => {
    console.log(data);// [1.txt內容,2.txt內容]
  },
  err => {
    console.log(err);
  }
);
複製程式碼

Promise.race()

  • 用法跟Promise.all()很像,指的是誰跑得快,執行誰的回撥。
let fs = require("fs");
function read(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, 'utf8', function(err, data) {
      if (err) return reject(err);
      resolve(data);
    });
  });
}
Promise.all([read("1.txt"), read("2.txt")]).then( //可以then說明Promise.all()返回結果也是promise
  data => {
    console.log(data);// [1.txt或者2.txt內容] 
  },
  err => {
    console.log(err);
  }
);
複製程式碼

讀到這裡,相信大家看到這裡都應該大概對promise有一定的瞭解,下一章帶領大家手寫一套符合promise A+規範的程式碼。

相關文章