一文看懂JS異步編程(Promise)

前言

JS中異步編程主要分爲四種,其中回調和生成器不是這篇文章的重點,本文主要集中在Promise和async, await上面。

Promise

首先我們看Promise的幾個特點:

  1. 回調函數延遲綁定即then方法,它可以接受兩個回調函數作爲參數。第一個回調函數是Promise對象的狀態變爲resolved時調用,第二個參數可選,一般使用catch觸發,無論那種方式都是把回調函數延遲執行。
  2. 返回值穿透。
readFilePromise('1.json').then(data => {
    return readFilePromise('2.json');
}).then(data => {
    return readFilePromise('3.json');
}).then(data => {
    return readFilePromise('4.json');
});

可以看到then方法返回的Promise可以在後面繼續使用。

  1. 錯誤冒泡,整個thenable鏈式調用發生的每一處錯誤都可以由最後一個catch捕獲。

then方法

then毫無疑問是這些方法種最重要的,我學習鏈式調用時下面代碼解答了我很多疑惑。

注意then接收兩個參數,都是函數,第二個可選。

同時函數返回的可以是一個值也可以是一個Promise,如果是前者,他會調用一個Promise包裹傳遞給後面使用;如果是後者同樣也會調用給後面使用。

var p = new Promise(function(resolve, reject){
  resolve(1);
});
p.then(function(value){               //第一個then
  console.log(value);
  return value*2;
}).then(function(value){              //第二個then
  console.log(value);
}).then(function(value){              //第三個then
  console.log(value);
  return Promise.resolve('resolve'); 
}).then(function(value){              //第四個then
  console.log(value);
  return Promise.reject('reject');
}).then(function(value){              //第五個then
  console.log('resolve: '+ value);
}, function(err){
  console.log('reject: ' + err);
})

接着來看一段執行順序的判斷:

var p1 = new Promise( function(resolve,reject){
  console.log('start1')
  resolve( 1 );	  
});

p1.then(
  function(value){
    console.log('p1 then value: ' + value);
  }
).then(
  function(value){
    console.log('p1 then then value: '+value);
  }
);

var p2 = new Promise(function(resolve,reject){
  resolve( 2 );	
});

p2.then(
  function(value){
    console.log('p2 then value: ' + value);
  }
).then(
  function(value){
    console.log('p2 then then value: ' + value);
  }
).then(
  function(value){
    console.log('p2 then then then value: ' + value);
  }
);
console.log('start2')

最後的執行結果爲:

VM382:2 start1
VM382:33 start2
VM382:8 p1 then value: 1
VM382:22 p2 then value: 2
VM382:12 p1 then then value: undefined
VM382:26 p2 then then value: undefined
VM382:30 p2 then then then value: undefined

resolve和reject

關於resolve,它可以接受普通值,也可以接收一個Promise

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))

如這一段程序,3000ms之前p1的狀態是pendding,由於這是p2中resolve依賴p1的狀態,所以p2的狀態我們可以忽略了。

這時p2走then方法,result即爲一個Promise,狀態pendding。

3000ms後走catch,這是因爲p1狀態改變,而p2直接轉發了p1的reject。

all和race

一個是都完成纔算成功,一個是誰跑得快誰成功。

當然關於all和race還有一些細節,如傳的是值而不是promise的話會先進行Promise處理;error若在Promise中聲明,是不會走all的catch方法的等等。

發佈了386 篇原創文章 · 獲贊 411 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章