JavaScript Promise(基礎)

afan發表於2018-06-25

1、Promise是什麼?

  • promsie是ES6新增的一個特性,它已經列入ES6的正式規範中
  • promise是抽象處理物件以及對其進行各種操作的元件,是一種非同步流程的控制手段。
  • javaScript和Node都是單執行緒非阻塞的,所以就會有非同步回撥的問題,promise就是為了解決這類問題的。
  • Promise可以支援多個併發的請求,獲取併發請求中的資料。
  • Promise可以使用鏈式呼叫的方法來組織程式碼,所以使用Promise物件後,就可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀讓程式碼更加的直觀。
示例:
$.ajax(url1, function(data1){
    // do something...
    $.ajax(url2, function(data2){
        // do something...
        $.ajax(url3, function(data3){
            // do something...
            done(data3); // 返回資料
        });
    });
});
複製程式碼

未使用promise,回撥必須層層巢狀(回撥地獄),程式碼難以維護,第一的輸出是第二個的輸入時,需要等待上一個操作完成才可以進行下一個操作,造成不必要的等待。


2、Promise的狀態

2.1 Promise物件有三種狀態
  • Pending(等待態)
    • 既不是resolve也不是reject的狀態,也就是promise物件剛建立後的初始化狀態;
  • Resolved/Fulfilled(成功態)
    • resolve(成功)時,此時會呼叫onFuifilled;
  • Rejected(失敗態)
    • reject(失敗)時,此時會呼叫onRejected;

promise只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

2.2 狀態一旦改變就不會再變,任何時候都可以得到這個結果。
  • 如果一旦promise成功了就不能失敗,相反也是一樣的,只有狀態是等待的狀態時才可以轉化狀態
    • promise物件的狀態改變,只有兩種可能:從Pending變為Resolved和從Pending變為Rejected

pending->fulfilledpending->rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果.

2.3 Promise的缺點
  • 無法取消,一旦新建就會立即執行,無法中途取消。
  • 如果不設定回撥函式,promise內部丟擲的錯誤,不會反應到外部。
  • 當處於pending狀態時,無法確定進展到哪一階段,剛開始還是即將完成。

3、Promise的使用

3.1基本用法
  • 首先要new一個Promise,將Promise例項化
  • 例項化的promise可以傳兩個引數,一個是成功之後的resolve,一個是失敗之後的reject
    • Promise本省只有一個引數,叫executor(執行器),預設new時就會呼叫
  • 每一個Promise的例項上都有一個then方法(非同步的),可以用then方法分別指定Resolved狀態和Reject狀態的回撥函式

程式碼示例: 預設promise中的executor預設執行

let p=new Promise((resolve,reject)=>{
    console.log(1);
});
console.log(2);
複製程式碼

執行順序

程式碼示例: 呼叫onFuifilled

let p=new Promise((resolve,reject)=>{
  resolve('成功');
});

p.then((value)=>{//value成功的原因
  console.log(value);
},(err)=>{//err失敗的原因
  console.log(err);
})
複製程式碼

成功

程式碼示例: 呼叫onRejected

let p=new Promise((resolve,reject)=>{
  reject('失敗');
});

p.then((value)=>{//value成功的原因
  console.log(value);
},(err)=>{//err失敗的原因
  console.log(err);
})
複製程式碼

失敗

程式碼示例: 成功了就不能失敗,相反也一樣

let p=new Promise((resolve,reject)=>{//
  resolve('成功');
  reject('失敗');
});

p.then((value)=>{//value成功的原因
  console.log(value);
},(err)=>{//err失敗的原因
  console.log(err);
})
複製程式碼

成功就不能失敗

程式碼示例: 成功了就不能失敗,相反也一樣

let p=new Promise((resolve,reject)=>{
    throw new Error('發生錯誤');
});
p.then((value)=>{//value成功的原因
	console.log(value);
},(err)=>{//err失敗的原因
	console.log(err);
})
複製程式碼

發生錯誤

3.2鏈式操作
  • 通過維護狀態、傳遞狀態的方式來使回撥能夠及時的呼叫,上一個操作完成之後才可以進行下一個操作,相比callback更靈活簡單
  • promise實現鏈式呼叫返回的並不是this,而是一個新的promise

程式碼示例:

Promise1().then((value)=>{
  console.log(valuse);
  return Promise2();
}).then((value)=>{
  console.log(value);
  return Promise3();
}).then((value)=>{
  console.log(value);
})//可以then到天荒地老

function Promise1(){
  return new Promsie((resolve,reject)=>{
    setTimeout(function(){//非同步操作
      console.log('非同步1');
      resolve('非同步1傳的值');
    },1000);
  })
}
function Promise2(){
  return new Promsie((resolve,reject)=>{
    setTimeout(function(){//非同步操作
      console.log('非同步2');
      resolve('非同步2傳的值');
    },3000);
  })
}
function Promise3(){
  return new Promsie((resolve,reject)=>{
    setTimeout(function(){//非同步操作
      console.log('非同步3');
      resolve('非同步3傳的值');
    },2000);
  })
}
複製程式碼

輸出的值為: 非同步1 非同步1傳的值 非同步2 非同步2傳的值 非同步3 非同步3傳的值

3.2 Promise的catch方法
  • catch方法是then(onFulfilled,onRejected)方法中onRejected函式的簡單寫法,也就是可以寫成then(fn).catch(fn),相當於then(fn).then(null,fn);

程式碼示例:

let p=((isReady)=>{
  return new Promise(()=>{
    if(isready){
      return resolve('hello');
    }else{
      return reject('failure');
    }
  });
})

p(true).then((value)=>{
    console.log('resolved');
    console.log(value);
    console.log(aa); 
  }).catch((err)=>{
    console.log('rejected');
    console.log(err);
  });
複製程式碼

輸出的值為: resolved hell rejected ReferenceError: aa is not defined...

3.3 promise.all方法
  • promise.all接收一個為promise物件的陣列作為引數,當這個陣列裡所有的promise物件都變為resolve時,該方法才會返回。

程式碼示例:

let p1=new Promise((resolve,reject)=>{
  setTimeout(function(){
    resolve('Promise1');
  },1000);
})
let p2=new Promise((resolve,reject)=>{
  setTimeout(function(){
    resolve('Promise2');
  },3000);
})

Promise.all([p1,p2]).then((result)=>{
  console.log(result);
})
複製程式碼

輸出結果 ['Promise1','Promise2']

3.4 promise.race方法
  • race的意思賽跑,也就是看誰跑的快,跑的快的就贏了。因此,promise.race也是傳入一個陣列,但是與promise.all不同的是,promise.race只返回跑的快的值。

程式碼例項:

  let p1=new Promise((resolve,reject)=>{
    setTimeout(function(){
      console.log(1);
      resolve('Promise');
    },3000);
  })
  let p2=new Promise((resolve,reject)=>{
    console.log(2);
    resolve('Promise2');
  },1000)

  Promise.race([p1,p2]).then((result)=>{
    console.log(result);
  })
複製程式碼

輸出結果: 2 Promised 1

  • 可以看到傳的值中,只有p2的返回了,但p1沒有停止,依然執行。

Promise的基礎就到這裡了,如果您覺得文章有用請點贊!!!

相關文章