溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中Promise的使用詳解

發(fā)布時間:2020-10-24 15:42:13 來源:腳本之家 閱讀:117 作者:hebedich 欄目:web開發(fā)

Promise是ES6中的函數(shù),規(guī)范了如何處理異步任務的回調(diào)函數(shù),功能類似于jQuery的defferred。簡單說就是通過promise對象的不同狀態(tài)調(diào)用不同的回調(diào)函數(shù)。目前IE8及以下不支持,其他瀏覽器都支持。

promise對象的狀態(tài),從Pending轉(zhuǎn)換為Resolved或Rejected之后,這個promise對象的狀態(tài)就不會再發(fā)生任何變化。

使用步驟:

var promise = new Promise(function(resolve, reject) {

 // 異步任務,通過調(diào)用resolve(value) 或 reject(error),以改變promise對象的狀態(tài);改變狀態(tài)的方法只能在此調(diào)用。

//promise狀態(tài)改變后,會調(diào)用對應的回調(diào)方法

});

promise.then(function(value){//resolve時的回調(diào)函數(shù),參數(shù)由異步的函數(shù)傳進來})

.catch(function(error){//發(fā)生異常時或明確reject()時的回調(diào)函數(shù)})

 具體使用:

function getURL(URL) {           //因為promise創(chuàng)建時即執(zhí)行,所以用工廠函數(shù)封裝promise對象
  return new Promise(function (resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', URL, true);
    req.onload = function () {
      if (req.status === 200) {
        resolve(req.responseText);
      } else {
        reject(new Error(req.statusText));
      }
    };
    req.onerror = function () {
      reject(new Error(req.statusText));
    };
    req.send();
  });
}
// 運行示例
var URL = "http://httpbin.org/get";
getURL(URL).then(function onFulfilled(value){
  console.log(value);
}).catch(function onRejected(error){
  console.error(error);
});

Promise的回調(diào)只有異步方式,即使是同步任務的回調(diào)也是異步執(zhí)行 。

var promise = new Promise(function (resolve){
  console.log("inner promise");         // 執(zhí)行1:同步任務先執(zhí)行
  resolve(‘callBack');
});
promise.then(function(value){
  console.log(value);              // 執(zhí)行3:雖然注冊時狀態(tài)為resolved,但回調(diào)仍是異步的;
});
console.log("outer promise");          // 執(zhí)行2:同步代碼先執(zhí)行


 

promise的方法鏈

then方法注冊的回調(diào)會依次被調(diào)用,每個then方法之間通過return 返回值傳遞參數(shù)。但是回調(diào)中的異常會導致跳過之間then的回調(diào),直接調(diào)用catch的回調(diào),之后再繼續(xù)調(diào)用剩下的then的回調(diào)。在then(onFulfilled, onRejected)中,onFulfilled的異常不會被自己的onRejected捕獲,所以優(yōu)先使用catch。

 promise .then(taskA) .then(taskB) .catch(onRejected) .then(finalTask);

 taskA拋異常,taskB被跳過,finalTask仍會被調(diào)用,因為catch返回的promise對象的狀態(tài)為resolved。

then方法內(nèi)可以返回3種值

1. 返回另一個promise對象,下一個then方法根據(jù)其狀態(tài)選擇onFullfilled/onRejected回調(diào)函數(shù)執(zhí)行,參數(shù)仍由新promise的resolv/reject方法傳遞;

2. 返回一個同步值,下一個then方法沿用當前promise對象的狀態(tài),無需等異步任務結(jié)束會立即執(zhí)行;實參為上一then的返回值;如果沒有return,則默認返回undefined;

3. 拋出異常(同步/異步):throw new Error(‘xxx');

then不僅是注冊一個回調(diào)函數(shù),還會將回調(diào)函數(shù)的返回值進行變換,創(chuàng)建并返回一個新promise對象。實際上Promise在方法鏈中的操作的都不是同一個promise對象。

var aPromise = new Promise(function (resolve) {
  resolve(100);
});
var thenPromise = aPromise.then(function (value) {
  console.log(value);
});
var catchPromise = thenPromise.catch(function (error) {
  console.error(error);
});
console.log(aPromise !== thenPromise); // => true
console.log(thenPromise !== catchPromise);// => true

Promise.all()靜態(tài)方法,同時進行多個異步任務。在接收到的所有promise對象都變?yōu)镕ulFilled 或者Rejected 狀態(tài)之后才會繼續(xù)進行后面的處理。

Promise.all([promiseA, promiseB]).then(function(results){//results是個數(shù)組,元素值和前面promises對象對應});

// 由promise對象組成的數(shù)組會同時執(zhí)行,而不是一個一個順序執(zhí)行,開始時間基本相同。
function timerPromisefy(delay) {
  console.log('開始時間:”'+Date.now()) 
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(delay);
    }, delay);
  });
}
var startDate = Date.now();
Promise.all([
  timerPromisefy(100),    //promise用工廠形式包裝一下
  timerPromisefy(200),
  timerPromisefy(300),
  timerPromisefy(400)
]).then(function (values) {
  console.log(values);  // [100,200,300,400]
});

不同時執(zhí)行,而是一個接著一個執(zhí)行promise

//promise factories返回promise對象,只有當前異步任務結(jié)束時才執(zhí)行下一個then
function sequentialize(promiseFactories) {
  var chain = Promise.resolve();
  promiseFactories.forEach(function (promiseFactory) {
    chain = chain.then(promiseFactory);
  });
  return chain;
}

Promise.race()同all()類似,但是race()只要有一個promise對象進入 FulFilled 或者 Rejected 狀態(tài)的話,就會執(zhí)行對應的回調(diào)函數(shù)。不過在第一個promise對象變?yōu)镕ulfilled之后,并不影響其他promise對象的繼續(xù)執(zhí)行。

//沿用Promise.all()的例子
Promise.race([
  timerPromisefy(1),
  timerPromisefy(32),
  timerPromisefy(64),
  timerPromisefy(128)
]).then(function (value) {
  console.log(values);  // [1]
});

Promise.race()作為定時器的妙用

Promise.race([
  new Promise(function (resolve, reject) {
    setTimeout(reject, 5000);     // timeout after 5 secs
  }),
  doSomethingThatMayTakeAwhile()
]);  

在then中改變promise狀態(tài)

因為then的回調(diào)中只有value參數(shù),沒有改變狀態(tài)的方法(只能在構(gòu)造方法的異步任務中使用),要想改變傳給下一個then的promise對象的狀態(tài),只能重新new一個新的Promise對象,在異步任務中判斷是否改變狀態(tài),最后return出去傳給下一個then/catch。

var promise = Promise.resolve(‘xxx');//創(chuàng)建promise對象的簡介方法
promise.then(function (value) {
  var pms=new Promise(function(resolve,reject){
    setTimeout(function () {
      // 在此可以判斷是否改變狀態(tài)reject/resolve
      Reject(‘a(chǎn)rgs');
    }, 1000);
  })
  return pms;  //該promise對象可以具有新狀態(tài),下一個then/catch需要等異步結(jié)束才會執(zhí)行回調(diào);如果返回普通值/undefined,之后的then/catch會立即執(zhí)行
}).catch(function (error) {
  // 被reject時調(diào)用
  console.log(error)
});        

獲取兩個promises的結(jié)果

//方法1:通過在外層的變量傳遞
var user;
getUserByName('nolan').then(function (result) {
  user = result;
  return getUserAccountById(user.id);
}).then(function (userAccount) {
  //可以訪問user和userAccount
});

//方法2:后一個then方法提到前一個回調(diào)中
getUserByName('nolan').then(function (user) {
  return getUserAccountById(user.id).then(function (userAccount) {
    //可以訪問user和userAccount
  });
});


 

注意使用promise時的整體結(jié)構(gòu)

假定doSomething()和doSomethingElse()都返回了promise對象

常用方式:

doSomething().then(doSomethingElse).then(finalHandler);
doSomething
|-----------------|
         doSomethingElse(resultOfDoSomething)  //返回新promise,下一個then要收到新狀態(tài)才執(zhí)行
         |------------------|
                   finalHandler(resultOfDoSomethingElse)
                   |---------------------|

常用變通方式:

doSomething().then(function () { return doSomethingElse();}).then(finalHandler);
doSomething
|-----------------|
         doSomethingElse(undefined) //then外層函數(shù)的arguments[0]== resultOfDoSomething
         |------------------|
                   finalHandler(resultOfDoSomethingElse)
                   |------------------| 

錯誤方式1:

doSomething().then(function () { doSomethingElse();}).then(finalHandler);
doSomething
|-----------------|
         doSomethingElse(undefined)  //雖然doSomethingElse會返回promise對象,但最外層的回調(diào)函數(shù)是return undefined,所以下一個then方法無需等待新promise的狀態(tài),會馬上執(zhí)行回調(diào)。
         |------------------|
         finalHandler(undefined)
         |------------------|

錯誤方式2:

doSomething().then(doSomethingElse()).then(finalHandler);
doSomething
|-----------------|
doSomethingElse(undefined)     //回調(diào)函數(shù)在注冊時就直接被調(diào)用
|----------|
         finalHandler(resultOfDoSomething)
         |------------------|

 

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI