javascript異步操作 Promise

語言特色

javascript 是一門單線程語言,意思就是同時只能執行一個任務,其他任務必須排隊等待。
爲什麼搞成單線程原因是因爲一個如果一個線程是在網頁上修改DOM,另一個線程在刪除DOM。這樣肯定不行。JavaScript 從誕生起就是單線程,原因是不想讓瀏覽器變得太複雜,因爲多線程需要共享資源、且有可能修改彼此的運行結果,對於一種網頁腳本語言來說,這就太複雜了。這種的好處是實現起來比較方便,單壞處就是隻要一個任務消耗的時間多,就會造成後面的任務排隊,會拖延整個程序的執行。這種慢的原因不是CPU忙不過來,而是單純的因爲一個任務執行需要很長時間,比如 Ajax請求等。JavaScript 語言的設計者意識到,這時 CPU 完全可以不管 IO 操作,掛起處於等待中的任務,先運行排在後面的任務。等到 IO 操作返回了結果,再回過頭,把掛起的任務繼續執行下去。這種機制就是 JavaScript 內部採用的“事件循環”機制(Event Loop)。

同步任務 || 異步任務

所有的任務可以分爲同步任務和異步任務。
同步任務是指不會被引擎掛起,在主線程上排隊執行任務。只有前一個任務執行完畢,纔會執行後一個任務。

異步任務 是指會被掛在引擎,不進入主線程,而是會進入任務隊列的任務。只有引擎認爲某個任務可以執行了,比如Ajax從服務器返回了數據,該任務採用回調的形式會進入主線程來執行。排在異步任務後面的代碼不會等待異步任務有結果,而是會立即執行。因此異步任務不會有阻塞效應。

任務隊列和事件循環

Javascript運行是除了一個正在運行的主線程以外,引擎還提供了任務隊列,裏面是各種需要當前程序處理的異步任務。
首先,主線程會執行所有的同步任務,同步任務被執行完以後會去看任務隊列,如果滿足條件,那麼異步任務就會重新進入主線程開始執行。這個時候它就變成了同步任務。等到執行完,下一個異步任務就會進入主線程,直到全部任務執行完。

異步操作解決方案

promise對象是Javascript的異步操作解決方案,爲異步操作提供統一接口。Promise可以讓異步操作寫起來,就像在寫同步操作一樣,而不必一層層嵌套回調函數。
首先,Promise是一個對象,也是一個構造函數。

function f1(resolve,reject){
  // 異步操作
  
}

let p1=new Promise(f1);

Promise構造函數接收回調函數f1作爲參數,f1 裏面的是異步操作的代碼,然後返回的p1就是 一個Promise的實例。
Promsie 的設計思想是所有的異步任務都返回一個Promise實例。Priomse實例有一個then 方法,用來指定下一步的回調函數。

var p1=new Promise(f1);
p1.then(f2);

上面的代碼中,f1的異步操作執行完,就會執行f2.

// 傳統寫法
step1(function (value1) {
  step2(value1, function(value2) {
    step3(value2, function(value3) {
      step4(value3, function(value4) {
        // ...
      });
    });
  });
});

// Promise 的寫法
(new Promise(step1))
  .then(step2)
  .then(step3)
  .then(step4);

可以看出promise寫法使程序流程變得非常清楚。

Promise 對象的狀態

Promise對象具有3中狀態。
1.未完成
2.異步操作成功
3.異步操作失敗

狀態變化只有兩種:
未完成----失敗
未完成–成功

因此Promise最終結果只有兩種:

  • 異步操作成功,Promise實例返回一個值。
  • 異步操作失敗,Promsie實例返回error.

Promise 構造函數

Javascript提供原生的構造函數,用來生成Promise實例。

var promise = new Promise(function(resolve, reject) {
				if ( /* 異步操作成功 */ ) {
					resolve(value);
				} else { /* 異步操作失敗 */
					reject(new Error());
				}
			});

上面代碼中Promise構造函數接收一個函數,該函數的兩個參數分別是resolve,reject。他們是兩個函數,由Javascript來提供,不用自己實現。
resolve的作用是將Promise實例的狀態從未完成到成功,並且把異步操作的結果作爲參數傳遞出去。reject函數的作用是將Promise實例的狀態從未完成變爲失敗,並將錯誤傳遞出去。

Promise.prototype.then

Promise實例的then方法用來添加回調函數。
then方法可以接收兩個參數,第一個是異步操作成功時的回調函數,第二個是異步操作失敗時的回調函數。

          var p1=new Promise(function(resolve,reject){
				 resolve("success")
			});
			p1.then(console.log,console.error);    //success
			
			var p2=new Promise(function(resolve,reject){
				reject("error");
			});
			p2.then(console.log,console.error);   //error

由上面的代碼可以看出 p1,p2都是Promise的兩個實例,他們的then方法會執行兩個回調函數,第一個會在實例成功的時候執行,第二個會在實例失敗的時候執行。第二個方法可以省略。
Promse 的then方法具有鏈式性。下面的代碼中有4個then,意味着只有前一個返回成功,下一個方法纔會執行。

p1
  .then(step1)
  .then(step2)
  .then(step3)
  .then(
    console.log,
    console.error
  );

實例 圖片加載

var preloadImage=function(path){
				return new Promise(function(resolve,reject){
					let image=new Image();
					image.onload=resolve;
					image.onerror=reject;
					image.src=path;
				});
			}
			
			preloadImage('https://example.com/my.jpg').then(
			  function(e){
				  document.body.append(e.target);
			  }
			).then(function(){
				console.log("加載完成。");
			});
			
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章