1. 概述
Promise對象是ES6提出的的異步編程的規范。說到異步編程,就不得不說說同步和異步這兩個概念。
從字面意思理解同步編程的話,似乎指的是兩個任務同步運行,如果這樣理解就錯了(至少筆者再沒有接觸到這個概念的時候有這種誤解)。同步和異步指的是代碼指定執行的順序(結構化編程范式的執行順序總是由上至下,由前往后的),如果執行的順序與代碼的相同,就是同步;如果不同,就是異步。
最初,操作系統都是基于命令行的,所有的的語言設計出來也天然是同步的語句,在這種情況下,也不需要異步編程。但是很快,圖形操作界面就出來了,所有的程序設計語言都不得不跟GUI打交道了。我們必須了解的是,GUI程序是一個不停繪制的界面程序:
1
2
3
4
5
|
while (done) { dosomething(); drawGUI(); } |
如果每個循環中執行的任務dosomething()的事件太長,就會導致界面遲遲得不到繪制命令,直觀的表現就是卡頓。為了解決這個問題,使用JavaScript作為腳本的瀏覽器一般都會采用事件循環(Event Loop)的機制:
- 將耗時的行為規定為事件,事件與響應回調函數綁定。
- 每個循環,優先處理同步代碼。
- 同步代碼完成,按照先后順序遍歷事件。
- 在剩下的沒有同步代碼的循環中,依次執行事件的相應函數。
這樣,在單線程的情況下,就修改了任務的執行順序,實現了異步的機制。因為同步的行為總是很快完成及時進行了界面繪制,界面卡頓的現象也大為改善了。
事件循環機制將UI設備的輸入輸出規定為事件,實際上,耗時的行為非常多,但是一般都與IO相關,與IO相關的行為,JavaScript都提供了異步行為的代碼。例如,這里要用的一個加載圖片的實例。
2. 詳論
首先準備一個HTML頁面PromiseTest.html,在這個HTML頁面中加載JS的腳本PromiseTest.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<!DOCTYPE html> < html > < head > < meta charset = "utf-8" > < script src = "./3rdParty/jquery-3.5.1.js" ></ script > < title >樣例</ title > </ head > < body > < div id = "container" > </ div > < script src = "./PromiseTest.js" ></ script > </ body > </ html > |
原生的JS的圖像對象Image,是通過事件的形式來實現圖像的異步加載的:
1
2
3
4
5
6
7
|
$( function () { var img = new Image(); img.onload = function () { $(img).appendTo($( '#container' )); }; img.src = "./img.jpg" ; }); |
為Image的事件句柄onload,添加一個相應函數,當圖像裝載完成之后,就將裝載好的Image添加到HTML頁面的某個div元素子節點下。通過瀏覽器打開這個頁面,會直接顯示對應地址的圖片。
這個JS腳本當然也可以通過Promise來改寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
$( function () { function getImg(uri){ return new Promise( function (resolve, reject){ var img = new Image(); img.onload = function () { resolve(img); }; img.onerror = function () { reject(Error( "Load Image Error!" )); } img.src = uri; }); } var imgUri = "./img.jpg" ; getImg(imgUri).then( function (img){ $(img).appendTo($( '#container' )); }, function (error){ console.error( "Failed!" , error); }) }); |
粗看起來,使用Promise,似乎使得程序顯得更加復雜和繁復了。但是我們要深入理解Promise機制的內涵,這樣設計并不是為了好玩。
- Promise對象代表的是一個預定要做、但是還未開始做的行為。既然是一個行為,當然得進行計劃,并對行為結果做出規定:如果成功了,就執行resolve;如果失敗了,就執行reject。一般我們可以定義一個function,并且返回一個Promise對象。
- 調用返回Promise對象的function,這樣這個想要進行的行為就真正啟動了。不過resolve和reject只是兩個回調函數,那么就通過then方法來規定成功和失敗對應的真正的處理函數。
可以看到,這樣的設計看起來很繁復,但是卻很像是一個同步行為:規定一個未完成行為對象,行為完成了如何處理,行為失敗了又如何處理。而這也是Promise的目的:使得異步操作更像是一個同步的行為。
3. 參考
同步(Synchronous)和異步(Asynchronous)
簡述JS單線程異步實現原理
JavaScript 運行機制詳解:再談Event Loop
到此這篇關于JavaScript異步編程之Promise的初步使用的文章就介紹到這了,更多相關js Promise使用內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/charlee44/archive/2021/04/11/14644509.html