一文帶你輕鬆掌握Promise
前端js學習中,讓大家最難受的就是異步的問題,解決異步、回調地獄
等問題時你必須得學會promise,對於多數前端程式設計師來說promise簡直就是惡夢,這篇文章就是從簡單易懂的角度做為切入點,幫助大家輕鬆掌握promise
非同步程式設計
#想要學習promise,你必須懂得什麼是非同步程式設計!眾所周知,js語言是單執行緒
機制。所謂單線程就是按次序執行,執行完一個任務再執行下一個。但是不影響存在同步
和異步
的兩種操作,這兩種操作做事情其實都是在一條流水線上(單線程),只是這兩種操作在單線程上的執行順序不一樣罷了!當js觸發到非同步任務時,會將非同步任務交給瀏覽器處理,當執行有結果時,會把非同步任務的回呼函數插入待處理佇列的隊尾!
我們通俗的去解釋一下我們的非同步:非同步就是從主執行緒發射一個子執行緒來完成任務
,每一個任務都有一個或多個回呼函數(callback ),前一個任務結束後,不是執行後一個任務,而是執行回呼函數
,後一個任務則是不等前一個任務結束就執行
,所以程式的執行順序與任務的排列順序是不一致的、異步的.
該圖摘自於菜鳥教程中的
非同步編程
小節,幫助大家更好的理解什麼是異步!
回呼函數
#回呼函數的定義非常簡單:一個函數被當作一個
實參
傳入到另一個函數(外部函數
),而這個函數在外部函數內被調用,用來完成某些任務的函數。就稱為回呼函數
回呼函數的兩種寫法(實作效果相同
):
const text = () => { document.write('hello james') } setTimeout(text,1000)
setTimeout(()=>{ document.write("hello james") },1000)
這段程式碼中的setTimeout
就是一個消耗時間較長的過程,它的第一個參數是個回呼函數
,第二個參數是毫秒數
,這個函數執行之後會產生一個子線程,子線程會等待1 秒,然後執行回呼函數"text"
,在文字中輸出hello james
setTimeout會在子線程中等待1秒,但是主執行緒的運行不會受到影響!例如以下程式碼:
setTimeout(()=>{ document.write("hello davis") },1000) console.log('123456');
在這裡會先列印出來
123456
(主執行緒
),然後一秒鐘後在文字中輸出hello davis
(子執行緒
)
#回呼地獄
##回呼地獄這個詞聽起來就非常的高大上,想要接觸Promise之前,必須懂得什麼是
回調地獄,以及為什麼會產生回調地獄?
先來看看概念:
當一個回呼函數嵌套一個回呼函數的時候就會出現一個巢狀結構當巢狀的多了就會出現回呼地獄的情況。
舉個例子:#我們發送三個ajax 請求:
- #第一個正常發送
- ##第二個請求需要第一個請求的結果中的某一個值作為參數
- 第三個請求需要第二個請求的結果中的某一個值作為參數
:$.ajax({
url: '我是第一个请求',
type: 'get',
success (res) {
// 现在发送第二个请求
$.ajax({
url: '我是第二个请求',
type:'post',
data: { a: res.a, b: res.b },
success (res1) {
// 进行第三个请求
$.ajax({
url: '我是第三个请求',
type:'post',
data: { a: res1.a, b: res1.b },
success (res2) {
console.log(res2)
}
})
}
})
}
})
可維護性差Promise的狀態了,程式碼體驗非常的不良好,看一會就給看懵了,為了解決這個問題,於是,就引入了我們的
Promise
,用Promise去解決回調地獄問題!
#Promise
是非同步編程的一種解決方案
,比傳統的解決方案——回調函數和事件——更合理和更強大,它是一個ECMAScript 6 提供的類別
,目的是更加優雅地書寫複雜的非同步任務
。
Promise物件有以下兩個特點:
- 物件的狀態不受外界影響。 Promise物件代表一個非同步操作,有三種狀態:
- pending
(進行中)、
fulfilled
(已成功)和rejected
(已失敗)。只有非同步操作的結果,可以決定目前是哪一種狀態,任何其他操作都無法改變這個狀態
。這也是Promise這個名字的由來,它的英文意思是「承諾」
,表示其他手段無法改變。</li><li><p><code>一旦状态改变,就不会再变,任何时候都可以得到这个结果
。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
两个特点摘自于??阮一峰ES6文章
new Promise(function (resolve, reject) { // resolve 表示成功的回调 // reject 表示失败的回调 }).then(function (res) { // 成功的函数 }).catch(function (err) { // 失败的函数 })
出现了new
关键字,就明白了Promise
对象其实就是一个构造函数,是用来生成Promise
实例的。能看出来构造函数接收了一个函数作为参数,该函数就是Promise构造函数的回调函数
,该函数中有两个参数resolve
和reject
,这两个参数也分别是两个函数!
简单的去理解的话resolve
函数的目的是将Promise对象状态变成成功状态
,在异步操作成功时调用,将异步操作的结果,作为参数
传递出去。reject
函数的目的是将Promise对象的状态变成失败状态
,在异步操作失败时调用,并将异步操作报出的错误,作为参数
传递出去。
Promise实例生成以后,可以用then方法
分别指定resolved状态
和rejected状态
的回调函数。
代码示例:
const promise = new Promise((resolve,reject)=>{ //异步代码 setTimeout(()=>{ // resolve(['111','222','333']) reject('error') },2000) }) promise.then((res)=>{ //兑现承诺,这个函数被执行 console.log('success',res); }).catch((err)=>{ //拒绝承诺,这个函数就会被执行 console.log('fail',err); })
代码分析:
上边说到Promise是一个构造函数,new之后等于说调用了构造函数,构造函数中传的参数是一个函数,这个函数内的两个参数分别又是两个函数(
reslove
和reject
),虽然感觉很绕,但是理清思路会很清晰的!我们得到对象
promise
,promise对象中自带有两个方法then
和catch
,这两个方法中会分别再传入一个回调函数,这个回调函数的目的在于返回你所需要成功或失败的信息!那么怎么去调用这两个回调函数呢?
看下方图可以快速理解:
这两个函数分别做为参数(reslove
和reject
)传到上方的函数中去了.随后在构造函数的回调函数中写入异步代码
(例如:ajax
和定时器
),这里使用了定时器作为例子,如果你想表达的是成功回调,你可以在内部调用函数reslove('一般情况下是后端返回的成功数据)
。如果你想表达的是失败回调,你可以调用reject('一般情况下是后端返回的失败信息')
.
这些就是Promise执行的过程!虽然理解着很绕,但是多读几遍绝对有不一样的收获!
then
方法返回的是一个新的Promise实例
(注意:不是原来那个Promise实例
)。因此可以采用链式写法
,即then方法后面再调用另一个then方法
实际案例:
我想要实现在一个数组中查看一个帖子,但是我最终的目的是得到这个帖子下面的所有评论,这该怎么实现呢?
实现思路:
先从一个接口中获取这个帖子的信息,然后通过该帖子的帖子id
从而获取到该帖子下的所有评论
代码如下:
pajax({ url:"http://localhost:3000/news", data : { author : "james" } }).then(res=>{ return pajax({ url : "http://localhost:3000/comments", data : { newsId : res[0].id } }) }).then(res=>{ console.log(res); }).catch(err=>{ console.log(err); })
代码分析:
这里使用了一个Promise已经封装过的ajax,我们从第一个接口中得到了
帖子id
,然后在then中的函数发送第二个请求(携带了第一个请求返回过来的参数
),我们最后想要拿到第二个接口的结果,于是又有了一个then方法,但是在第一个then方法中要把一个新的Promise实例return
出去,这样的话,第二个then才起作用!(这是因为then
方法是Promise 实例
所具有的方法,也就是说,then方法是定义在原型对象Promise.prototype上的
)====>我们可以打印一下:console.log(Promise.prototype)
可以看的出来原型对象Promise.prototype
中是有then方法的!
Promise.all()
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
。
语法格式:
const p = Promise.all([p1, p2, p3]);
Promise.all()
方法接受一个数组
作为参数,p1、p2、p3都是 Promise 实例
,如果不是,就会调用Promise.reslove() [该方法可自行了解]
自动将参数转为 Promise 实例,再进一步处理。
说那么多白话没用,我们可以根据一个案例,就可以明白Promise.all()
的用途了。
实际案例:
如果你想实现一个效果:在一个页面中,等到页面中所有的请求返回数据后,再渲染页面,该怎么实现呢?(在实际开发中我们会看到loading
加载页面,等数据返回完后,loading加载页面会消失,整个页面就展现出来了,增强用户的体验。)
实现思路:
通过Promise.all()
方法,等多个接口全部接收到数据后,再统一进行处理,然后渲染页面
代码如下:
console.log("显示加载中") const q1 = pajax({ url:"http://localhost:3000/looplist" }) const q2 = pajax({ url:"http://localhost:3000/datalist" }) Promise.all([q1,q2]).then(res=>{ console.log(res) console.log("隐藏加载中...") }).catch(err=>{ console.log(err) })
代码分析:
在上方代码中,全局打印
显示加载中
是代替loading的页面,表示该页面现在正是loading
页面中,等到q1
和q2
所请求接口都得到返回的信息后,在then
方法中接收收据,并且可以进行渲染页面,同时隐藏了loading
加载页面!
小结
不论是在前端的项目开发中还是在前端的面试过程中,Promise的地位就是举足轻重的
,虽然解决异步编程的终极解决方案是async和await
,但是它们也是基于Promise封装而来的,在以往文章中,我就说过,学习编程重要的是搞懂某个技术是怎么实现的,而不是做一个cv侠
,多去思考,才能进步。继续加油吧,少年!
【相关推荐:javascript视频教程、编程基础视频】
以上是一文帶你輕鬆掌握Promise的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

在日常生活中,我們常常會遇到承諾與兌現之間的問題。無論是在個人關係中,或是在商業交易中,承諾的兌現都是建立信任的關鍵。然而,承諾的利與弊也常常會引起爭議。本文將探討承諾的利與弊,並給予一些建議,如何做到言出必行。承諾的利是顯而易見的。首先,承諾可以建立信任。當一個人信守承諾時,他會讓別人相信自己是個可信賴的人。信任是人與人之間建立的紐帶,它可以讓人們更加

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

Promise.resolve()詳解,需要具體程式碼範例Promise是JavaScript中一種用來處理非同步操作的機制。在實際開發中,常常需要處理一些需要依序執行的非同步任務,而Promise.resolve()方法就是用來傳回一個已經Fulfilled狀態的Promise物件。 Promise.resolve()是Promise類別的靜態方法,它接受一個
