中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

ES6中promise的作用是什么

發布時間:2021-01-20 16:11:11 來源:億速云 閱讀:664 作者:Leah 欄目:web開發

這篇文章給大家介紹ES6中promise的作用是什么,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

第一部分:什么是Promise

  看本文的最后一個例子,迅速理解。

  Promise是ES6中的一個內置的對象(實際上是一個構造函數,通過這個構造函數我們可以創建一個Promise對象),它是為了解決異步問題的。Promise的英文意思是承諾。

  Promise的特點如下:

?Promise有三種狀態:Pending(進行中)、Resolved(已完成)、Rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。這就是Promise。

?Promise一共有三種狀態,但是他們之間是如何轉化的呢? 其一: 從Pending(進行中)到Resolved(完成)。其二: 從Pending(進行中)到Rejected(已失敗)。 且只有這兩種形式的轉變,即使是Promise對象的結果也無力回天了。

  但是Promise也是有一定的缺點的,如在Pengding時,我們無法取消狀態,另外,我們沒法判斷Pending究竟是剛剛開始的Pending還是即將要完成的Pending。

第二部分:使用Promise

前言: 

 在下面例子的講解中,我們需要使用到setTimeout函數,這里首先說明setTimeout的一些重要用法。一般我們常用的如下所示:

    setTimeout(func(){}, 1000);

  即在1000ms之后執行func函數,但是其實setTimeout還可以傳入更多的參數。這篇博客做了講解,而這里為了了解下面的例子我們只需要知道,在chrome中可以傳入第三個、第四個參數....作為func()函數的參數傳遞進去,舉例如下:      

setTimeout(function (a, b) {
   console.log(a + b);
  }, 1000, 20, 50);

  最終的輸入結果是:70

  下面的代碼創建了一個Promise實例:

var promise = new Promise(function(resolve, reject) {
 // ... some code

 if (/* 異步操作成功 */){
 resolve(value);
 } else {
 reject(error);
 }
});

  其中,由于Promise是構造函數,所以我們使用new來創建一個對象即可, 值得注意的是:function(resolve, reject){}這個函數是必須要寫的,否則就不是Promise了。

  這個函數是為了初始化Promise對象,其中這個函數接受了兩個函數作為參數, 如果在函數體中我們執行了resolve函數,那么Promise的狀態就會由pending轉化為resolved(或fullfilled,兩者是相同的),類似的,如果我們執行了reject函數,pending就會變成 rejected。  

  注意: 這個例子的if語句不是必要的,這里想要表達的意思是如果得到了異步成功的相關結果,我們就將調用resolve,將pending轉化為resolved,并且將異步成功后的value值傳遞進去以便后面使用,說是以便后面使用是因為Promise還有一個then()方法,即可以定義在異步成功(或失敗)之后需要做的事情。這也就是resolve和reject內置函數存在的意義了。

 當創建了這個Promise對象之后,就一定會有一個結果了,但是成功和失敗還是不確定的,我們需要根據判斷結果的成功和失敗來做不同的事情,于是用到了then()方法,如下所示:

promise.then(function(value) {
 // success
}, function(error) {
 // failure
});

  下面是一個例子,并做了詳盡的說明:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>testsettimeout</title>
</head>
<body>
 <script>
 var promise = new Promise(function (resolve, reject) {
  console.log("good");
  var a = 10;
  var b = a + 25;
  if ( b === 35 ) {
   // 一旦異步執行成功,我們就調用內置的 resolve函數,將pending狀態轉化為resolved,并且傳入我們希望傳出的執行成功后的結果。
   // 注意: 這里一旦狀態轉變,那么后面就一定會調用then方法中的第一個參數的函數,然后將我們傳入給resolve的參數傳給then方法中的第一個方法作為參數,我們就可以在then的第一個方法中使用了。
   resolve(b);
  } else {
   reject("異步執行失敗");
  }
 });
 promise.then(function (value) {
  console.log("異步執行成功,輸出執行結果:" + value);
 }, function (error) {
  console.log("異步執行失敗,輸出執行結果:" + error);
 });
 </script>
</body>
</html>


而阮一峰老師所列的下面的這個例子可以清楚的看出promise就是異步的:

 let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
 });

 promise.then(function() {
  console.log('Resolved.');
 });

 console.log('Hi!');

最終的輸出結果是: Promise    Resolved    Hi

分析: 從這個例子中可以看出promise的異步,因為前面的兩部分代碼還沒有執行,就已經輸出了Hi。另外可以確定的是 Resolved 一定是在 Promise之后輸出的,這個順序是不可能有問題的。

下面的例子是一個異步添加圖片的url的例子    

function loadImageAsync(url) {
   return new Promise(function(resolve, reject) {
    var image = new Image();
    image.onload = function () {
     resolve(image);
    };
    image.onerror = function() {
     reject(new Error('Could not load image at' + url));
    }
    image.src = url;
   });
  }

如果加載成功就使用resolve方法,如果失敗就使用reject方法。

下面的例子是阮一峰老師封裝的Ajax的例子,是在太好,沒法不直接拿來參考~ 

var getJSON = function(url) {
 var promise = new Promise(function(resolve, reject){
 var client = new XMLHttpRequest();
 client.open("GET", url);
 client.onreadystatechange = handler;
 client.responseType = "json";
 client.setRequestHeader("Accept", "application/json");
 client.send();
 function handler() {
  if (this.readyState !== 4) {
  return;
  }
  if (this.status === 200) {
  resolve(this.response);
  } else {
  reject(new Error(this.statusText));
  }
 };
 });
 return promise;
};
getJSON("/posts.json").then(function(json) {
 console.log('Contents: ' + json);
}, function(error) {
 console.error('出錯了', error);
});

  這里應該大家都可以看懂,值得注意的是:handler這個處理函數的使用在這里顯得很巧妙。

第三部分: Promise.prototype.then()

  在上一部分,我們實際上已經介紹了then()方法,而這里需要強調的有兩點。

  第一: then()方法是Promise原型上定義的方法。

  第二:then()方法支持鏈式調用,上一個then()方法調用后返回的結果會傳給下一個then方法中。

第一:我們再chrome中輸入 Promise.prototype可以看到下面的例子:

ES6中promise的作用是什么

 可以看出在Promise的原型中確實是由then方法的。(注:比如我們想看Array這個內置對象有哪些方法,我們就可以直接在chrome中輸入Array.prototype,然后就可以看到對應方法的列表了)

 第二: then()的作用是為Promise實例添加狀態改變時的回調函數。前面說過,then方法的第一個參數是Resolved狀態的回調函數,第二個參數(可選)是Rejected狀態的回調函數。

    then()由于支持鏈式調用,所以也可以寫成下面這樣:

getJSON("/posts.json").then(function(json) {
 return json.post;
}).then(function(post) {
 // ...
});

  第一個回調函數完成以后,會將返回結果作為參數,傳入第二個回調函數。

 看下面的這里例子:

getJSON("/post/1.json").then(function(post) {
 return getJSON(post.commentURL);
}).then(function funcA(comments) {
 console.log("Resolved: ", comments);
}, function funcB(err){
 console.log("Rejected: ", err);
});

  即第一個then又返回了一個promise,如何這個promise的狀態變成了 Resolved,那么就會執行第二個then的第一個函數, 如果變成了 Rejected,就會執行第二個第二個函數。

第四部分: Promise.prototype.catch()

   Promise.prototype.catch()方法實際上是then(null, rejection)方法的別名, 這里使用catch()純粹是為了便于使用和理解。

getJSON('/posts.json').then(function(posts) {
 // ...
}).catch(function(error) {
 // 處理 getJSON 和 前一個回調函數運行時發生的錯誤
 console.log('發生錯誤!', error);
});

  在之前的例子中,我們講解then()方法接受兩個參數,第一個參數是pending變成resolved之后執行的函數,它是必選的; 第二個參數是pending變成rejected之后執行的函數,它是可選的。

  我們建議,最后不要使用第二個參數,取而代之我們最好使用catch(),如下所示:

// bad
promise
 .then(function(data) {
 // success
 }, function(err) {
 // error
 });

// good
promise
 .then(function(data) { //cb
 // success
 })
 .catch(function(err) {
 // error
 });

  值得注意的是:catch()方法返回的還是一個Promise對象,我們可以在后面繼續使用then進行鏈式調用。

第五部分:Promise.all()

  Promise.all()方法用于將多個Promise實例包裝成一個新的Promise實例,如下所示:

var p = Promise.all([p1, p2, p3]);

  其中的p1,p2,p3都是Promise對象實例,如果不是,就會先調用下面講到的Promise.resolve方法,將參數轉為Promise實例,再進一步處理。

  p的狀態由p1,p2,p3決定, 分成下面的兩種情況:

?只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。

?只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

  讓我們看看下面的具體的例子:

// 生成一個Promise對象的數組
var promises = [2, 3, 5, 7, 11, 13].map(function (id) {
 return getJSON("/post/" + id + ".json");
});

Promise.all(promises).then(function (posts) {
 // ...
}).catch(function(reason){
 // ...
});

  在這個例子中,通過數組的map生成了6個Promise對象,然后作為參數傳遞給了Promise.all() 只有這6個Promise對象最終返回的都是 resolved時, 才會調用Promise.all()后面then()方法。

第六部分:Promise.race()

  該方法同樣是將多個Promise實例包裝成一個新的Promise實例,如下:

var p = Promise.race([p1, p2, p3]);

  在上面的代碼中,如果有一個Promise率先改變狀態,p的狀態就會跟著改變。

第七部分: Promise.resolve()

  如果我們希望將一個現有對象轉化為Promise對象,我們就可以使用Promise.resolve()方法。根據參數的不同可以分為4種情況:

(1)參數是一個Promise實例

  如果參數是Promise實例,那么Promise.resolve將不做任何修改、原封不動地返回這個實例。

(2)參數是一個thenable對象

  如果參數是一個thenable對象,即具有then()方法的對象,那么Promise.resolve()就會將該對象立即轉化成 Promise對象那個,并立即執行then方法。

(3)參數不是具有then方法的對象,或根本就不是對象

  如果參數是一個原始值,或者是一個不具有then方法的對象,則Promise.resolve方法返回一個新的Promise對象,狀態為Resolved。

(4)不帶有任何參數

第八部分: Promise.reject()

  Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態為rejected。

第九部分: 理解Promise

  它的作用就是如果前面的一段代碼非常的耗時,就會阻塞后面的某個代碼片段。  所以我們希望他不要阻塞后面的代碼,那么就讓他異步好了。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>testsettimeout</title>
</head>
<body>
 <div class="wrap">
  
 </div>
 <script>
 console.time("time");
 for (var i = 0; i < 50000; i++) {
  var li = document.createElement("li");
  document.querySelector(".wrap").append(li);
 }
 console.timeEnd("time");
 var a = 10;
 var b = a + 25;
 console.log( a);
 console.log(b);
 console.timeEnd("time");
 </script>
</body>
</html>

  最后的輸出結果是:

ES6中promise的作用是什么

  可以看到前面的代碼在阻塞后面的代碼。 導致后面的代碼無法運行。

 因為我們希望這個耗時的代碼越快執行越好,會非常嚴重的影響用戶體驗,所以把它放在了最前面,如果它沒有什么用,就放在了最后面了。

  但是后面的代碼我們也希望盡快執行啊,那么該怎么辦呢?  如果可以讓前面的代碼單獨在一個線程上運行, 而不影響后面的代碼運行就好了。

setTimeout()就可以做到,如下所示:

 console.time("time");
 setTimeout(function() {
  for (var i = 0; i < 50000; i++) {
     var li = document.createElement("li");
     document.querySelector(".wrap").append(li);
    }
    console.timeEnd("time");
 }, 0);
 var a = 10;
 var b = a + 25;
 console.log(a);
 console.log(b);
 console.timeEnd("time");

  最終的輸出結果如下:

ES6中promise的作用是什么

  可以看到在setTimeout中的函數一開始就執行了。

  但是為什么setTimeout的內容執行的這么慢呢? 我們再看一個例子

 console.time("time");
 setTimeout(function() {
  console.timeEnd("time");
 }, 0);

  結果如下:

time: 2.234ms

即 setTimeout 自身就會先消耗一定的時間。

ok,那么說了半天Promise到底怎么和他們比較呢? 他的價值在哪里呢?

價值都在這里了!看下面的這個例子:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>testsettimeout</title>
</head>
<body>
 <div class="wrap">
 </div>
 <script>
 let promise = new Promise(function(resolve, reject) {
  console.log('Promise! 我是Promise對象里的函數,我最早出現是因為我要給后面一個耗時的家伙提供數據a');
  var a = 20;
  resolve(a);
 });
 promise.then(function(value) {
  console.log('哈哈哈,我得到數據a了,要開始執行嘍。我是一個非常耗時的操作,依賴前面的數據,但是我想快一點執行,這有利于用戶體驗,所以別把我放在后頭啊;我被放在了一個新的線程上,不會阻塞別人的');
  for (var i = 0; i < 1000000; i++) {
  var li = document.createElement("li");
  document.querySelector(".wrap").appendChild(li);
  }
  console.log("執行完畢");
 });
 console.log('Hi! 我是什么都不依賴的程序,但我也想快一點執行,不能委屈我啊');
 </script>
</body>
</html>

ES6中promise的作用是什么

說明: 在已經執行過的情況下,錄制屏幕,然后按下刷新鍵,可以發現,在new Promise里的函數是立即執行的,緊接著是promise.then()之后的函數立即執行,而沒有等待then()函數,最后進入then()函數,說了一堆廢話,最后大約2 ~ 3s之后執行結束。故promise.then()函數才是真正的異步執行。

promise實現:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>promise</title>
</head>
<body>
 <script>
 function Mypromise(fn) {
  this.state = 'pending';
  this.value = void 0;
  this.doneList = [];
  this.failList = [];
  // 在創建一個promise的時候,需要傳遞一個fn函數,接受參數resolve和reject。 
  // resolve和reject目前還沒有定義,因為用戶是直接調用的,如resolve('success'),所以這個resolve方法是需要我們自己來定義的。
  var self = this;
  function resolve(value) {
  // 一旦resolve,狀態機的狀態由pending -> resolved
  // 并且在resolve的時候狀態必須是pending,才能轉換狀態。
  // 異步執行所有回調函數
  setTimeout(function () {
   if (self.state == 'pending') {
   self.state = 'resolved'
   self.value = value;
   // 一旦成功,我們就可以執行所有promise上掛載的 doneList 中所有的回調函數了,并將value值傳遞過去
   for (var i = 0; i < self.doneList.length; i++) {
    self.doneList[i](value);
   }
   }
  }, 0);
  }
  function reject(reason) {
  // 一旦reject,狀態機的狀態由pending -> rejected
  // 在reject的時候狀態必須是pending,才能轉化狀態。
  // 異步執行所有回調函數
  setTimeout(function () {
   if (self.state == 'pending') {
   self.state = 'rejected'
   self.value = reason;
   // 一旦失敗,我么就可以把所有的 failList 調用了,并且傳遞 reason
   for (var i = 0; i < self.failList.length; i++) {
    self.failList[i](reason);
   }
   }
  }, 0);
  }
  fn(resolve, reject);
 }
 Mypromise.prototype = {
  constructor: Mypromise,
  // then方法接受成功時的回調和失敗時的回調
  // 實際上,這里的then方法就像路由中的注冊路由一樣,是一個注冊的過程,而沒有真正的調用。
  // 并且then是支持鏈式調用的,所以then應該返回一個promise。 如果返回舊的,那么因為狀態不能改變,所以沒有意義,所以我么一定要返回一個新的promise,這樣這個狀態機才可以再次正常的工作。
  then: function (onResolved, onRejected) {
  var self = this;
  // 對于then而言,最終要返回一個新的promise,這樣才支持鏈式調用。
  var promise2;
  // 這里要做一個判斷,看傳遞進來的是否是一個函數,如果是,則不變,如果不是,就拒絕。
  // 如果是promise.then().then().then(function (value) {}); 我們還希望拿到value,那么就要把value在即使沒有用到onResolved的時候也傳遞下去。對于reason也是如此。
  onResolved = typeof onResolved == 'function' ? onResolved : function (value) {return value;}
  onRejected = typeof onRejected == 'function' ? onRejected : function (reason) { return reason;}
  // 下面這一部分是比較核心的內容,因為then最終要返回一個promise,但是,這個promise究竟應該怎么返回呢? 如果在then中,用戶就返回了promise,那么我們就用戶的,如果用戶用的不是promise,那么我么就要自己封裝好這個promise了。 
  // 注意: promise也是需要異步調用的,所以可以使用promise進行封裝。
  switch(this.state) {
   case 'resolved': 
   // 如果resolved,則返回一個新的promise
   return promise2 = new Mypromise(function (resolve, reject) {
    setTimeout(function () {
    try {
     // 這里相當于直接就給執行了,看看返回的是什么值,如果是promise,那么直接就使用這個promise了。 
     var x = onResolved(self.value);
     if (x instanceof Mypromise) {
     x.then(resolve, reject);
     }
    } catch (e) {
     reject(e);
    }
    }, 0)
   })
   case 'rejected': 
   // 如果rejected,同樣也需要返回一個新的promise
   return promise2 = new Mypromise( function (resolve, reject) {
    setTimeout(function () {
    try {
     var x = onRejected(self.value);
     if (x instanceof Mypromise) {
     x.then(resolve, reject);
     } 
    } catch (e) {
     reject(e);
    }
    }, 0);
   })
   // 如果是pending狀態,我們就不能確定使用什么,等到狀態確定之后才能決定。 
   case 'pending':   
   return promise2 = new Mypromise(function () {
    // 注意:一般then都是執行的這里, 即在then的時候進行注冊,把相應的成功的和失敗的都會初測在這里,push的是一個函數,所以這里的onResolved還是沒有執行的。
    setTimeout(function () {
    self.doneList.push(function (value) {
     try {
     var x = onResolved(self.value)
     if (x instanceof Mypromise) {
      x.then(resolve, reject)
     } else {
      onResolved(value);
     }
     } catch (e) {
      reject(e)
     }
    });
    console.log(self.doneList)
    self.failList.push(function (value) {
     try {
     var x = onRejected(self.data);
     if (x instanceof Mypromise) {
      x.then(resolve, reject);
     }
     } catch (e) {
     }
    });
    }, 0);
   })
   default: 
   console.log(this.state);
   return;
  }
  }, 
  catch: function (onRejected) {
   return this.then(null, onRejected);
  }
 }
 var promise = new Mypromise(function (resolve, reject) {
  if (5 > 3) {
  resolve('success');
  }
 });
 promise.then(function (value) {
  console.log('哈哈哈哈或');
 });
 </script>
</body>
</html>

關于ES6中promise的作用是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

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

AI

张家口市| 册亨县| 岳西县| 新沂市| 济南市| 师宗县| 敦煌市| 曲靖市| 凌海市| 乳源| 濮阳市| 阿尔山市| 托克逊县| 乐昌市| 祁门县| 保山市| 余姚市| 绵竹市| 奎屯市| 万载县| 麻栗坡县| 阜新| 民和| 峡江县| 炉霍县| 泽普县| 临夏县| 城固县| 枣阳市| 堆龙德庆县| 鲁甸县| 哈密市| 安顺市| 齐河县| 台州市| 滦平县| 洛扎县| 濮阳县| 张家口市| 祁连县| 红原县|