首頁  >  文章  >  web前端  >  JavaScript中Promise的使用

JavaScript中Promise的使用

高洛峰
高洛峰原創
2018-05-15 17:35:361279瀏覽

Promise是ES6中的函數,規範如何處理非同步任務的回呼函數,功能類似jQuery的defferred。簡單說就是透過promise物件的不同狀態呼叫不同的回呼函數。目前IE8及以下不支援,其他瀏覽器都支援。

promise物件的狀態,從Pending轉換為Resolved或Rejected之後,這個promise物件的狀態就不會再發生任何變化。

使用步驟:

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

 // 异步任务,通过调用resolve(value) 或 reject(error),以改变promise对象的状态;改变状态的方法只能在此调用。

//promise状态改变后,会调用对应的回调方法

});

promise.then(function(value){//resolve时的回调函数,参数由异步的函数传进来})

.catch(function(error){//发生异常时或明确reject()时的回调函数})

 具體使用:

function getURL(URL) {           //因为promise创建时即执行,所以用工厂函数封装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的回呼只有非同步方式,即使是同步任務的回呼也是非同步執行 。

var promise = new Promise(function (resolve){
  console.log("inner promise");         // 执行1:同步任务先执行
  resolve(‘callBack');
});
promise.then(function(value){
  console.log(value);              // 执行3:虽然注册时状态为resolved,但回调仍是异步的;
});
console.log("outer promise");          // 执行2:同步代码先执行

promise的方法鏈

then方法註冊的回調會依次被調用,每個then方法之間透過return 返回值傳遞參數。但回呼中的異常會導致跳過之間then的回調,直接呼叫catch的回調,之後再繼續呼叫剩下的then的回呼。在then(onFulfilled, onRejected)中,onFulfilled的異常不會被自己的onRejected捕獲,所以優先使用catch。

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

 taskA拋異常,taskB被跳過,finalTask​​仍會被調用,因為

 taskA拋異常,taskB被跳過,finalTask​​仍會被調用,因為

 taskA拋異常,taskB被跳過catch回傳的promise物件的狀態為resolved。

then方法內可以返回3種值

1. 返回另一個promise對象,下一個then方法根據其狀態選擇onFullfilled/onRejected回呼函數執行,參數仍由新promise的resolv /reject方法傳遞;

2. 傳回一個同步值,下一個then方法沿用當前promise物件的狀態,無需等非同步任務結束會立即執行;實參為上一then的回傳值;如果沒有return,則預設回傳undefined;

3. 拋出例外(同步/非同步):throw new Error('xxx');

then不僅是註冊一個回呼函數,還會將回調函數的回傳值進行變換,建立並傳回一個新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()靜態方法,同時進行多個非同步任務。在接收到的所有promise物件都變成FulFilled 或Rejected 狀態之後才會繼續進行後面的處理。

Promise.all([promiseA, promiseB]).then(function(results){//results是个数组,元素值和前面promises对象对应});

// 由promise对象组成的数组会同时执行,而不是一个一个顺序执行,开始时间基本相同。
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]
});

不同時執行,而是一個接著一個執行promise

//promise factories返回promise对象,只有当前异步任务结束时才执行下一个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 狀態的話,就會執行對應的回呼函數。不過在第一個promise物件變成Fulfilled之後,並不影響其他promise物件的繼續執行。

//沿用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狀態

因為then的回呼中只有value參數,沒有改變狀態的方法(只能在構造方法的非同步任務中使用),要改變傳給下一個then的promise對象的狀態,只能重新new一個新的Promise對象,在非同步任務中判斷是否改變狀態,最後return出去傳給下一個then/catch。

var promise = Promise.resolve(‘xxx');//创建promise对象的简介方法
promise.then(function (value) {
  var pms=new Promise(function(resolve,reject){
    setTimeout(function () {
      // 在此可以判断是否改变状态reject/resolve
      Reject(‘args');
    }, 1000);
  })
  return pms;  //该promise对象可以具有新状态,下一个then/catch需要等异步结束才会执行回调;如果返回普通值/undefined,之后的then/catch会立即执行
}).catch(function (error) {
  // 被reject时调用
  console.log(error)
});

取得兩個promises的結果

//方法1:通过在外层的变量传递
var user;
getUserByName('nolan').then(function (result) {
  user = result;
  return getUserAccountById(user.id);
}).then(function (userAccount) {
  //可以访问user和userAccount
});

//方法2:后一个then方法提到前一个回调中
getUserByName('nolan').then(function (user) {
  return getUserAccountById(user.id).then(function (userAccount) {
    //可以访问user和userAccount
  });
});

注意使用promise時的整體結構

假定doSomething()和doSomethingElse()都回傳了promise物件

#常用方式:

doSomething().then(doSomethingElse).then(finalHandler);
doSomething
|-----------------|
         doSomethingElse(resultOfDoSomething)  //返回新promise,下一个then要收到新状态才执行
         |------------------|
                   finalHandler(resultOfDoSomethingElse)
                   |---------------------|

常用變通方式:

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

錯誤方式1:

doSomething().then(function () { doSomethingElse();}).then(finalHandler);
doSomething
|-----------------|
         doSomethingElse(undefined)  //虽然doSomethingElse会返回promise对象,但最外层的回调函数是return undefined,所以下一个then方法无需等待新promise的状态,会马上执行回调。
         |------------------|
         finalHandler(undefined)
         |------------------|

錯誤方式2:

doSomething().then(doSomethingElse()).then(finalHandler);
doSomething
|-----------------|
doSomethingElse(undefined)     //回调函数在注册时就直接被调用
|----------|
         finalHandler(resultOfDoSomething)
         |------------------|
###更多JavaScript中Promise的使用相關文章請關注PHP中文網! ###
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn