<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Promise是ES6引入的非同步程式設計的新解決方案。語法上Promise是一個建構函式,用來封裝非同步操作並可以獲取其成功或失敗的結果。
Promise特點:
Promsie物件非同步操作有三種狀態,pending(進行中)、fulfilled(已成功)和reject(已失敗)。只有非同步操作才可以決定當前是哪種狀態;Promise狀態改變有兩種可能,從pending變為fulfidded和從pending變為rejected。狀態發生改變就不能再改變了,稱為:resolved(已定型)
Promise物件的作用:將非同步操作以同步操作的流程表達出來,避免層層巢狀的回撥函數,而且Promise提供了統一的介面,使得控制非同步操作更加容易。
Promise建構函式接收一個函數作為引數,該函數的兩個引數分別為:resolve 和 reject。
resolve:在非同步操作成功時呼叫,並將非同步操作的結果作為引數傳遞出去。
reject:在非同步操作失敗時呼叫,並將非同步操作報出的錯誤作為引數傳遞出去。
Promise範例生成後,可以用 then 方法分別指定 resolved 狀態和 rejected 狀態的回撥函數;而第一個回撥函數是 Promise 物件狀態變 resolved 時呼叫,第二個回撥函數是 Promise 物件的狀態變為 rejected 時呼叫。案例如下:
<script> // 範例化 Promise 物件,接收引數為函數型別值 const p = new Promise(function(resolve,reject){ // 封裝非同步操作 setTimeout(function(){ // 資料操作 // let data = '使用者資料' // resolve // resolve(data) let err = '資料讀取失敗' reject(err) },1000) }) // 呼叫 Promise 物件的 then 方法 // 資料呼叫成功,則呼叫下面第一個回撥,失敗則是第二個 p.then(function(value){//成功的形參 console.log(value); },function(reason){//失敗的形參 console.log(reason); }) </script>
Promise新建後會立即執行,然而 then 方法指定的回撥函數將在當前指令碼所有同步任務執行完才會執行。
<script> let p = new Promise(function(resolve,reject){ console.log('People'); // 資料操作 let data = 'World' resolve(data) }) p.then(function(value){ console.log(value); }) console.log('Hello'); </script>
<script> const p = new Promise((resolve,reject) =>{ // 1.建立物件 const xhr = new XMLHttpRequest() // 2.初始化 xhr.open("GET","https://ai.baidu.com/") // 3.傳送 xhr.send() // 4.繫結事件,處理響應結果 xhr.onreadystatechange = function(){ // 判斷 if(xhr.readyState ===4 ){ // 判斷響應碼 200-299 if(xhr.status >= 200 && xhr.status <300){ // 表示成功 resolve(xhr.response); }else{ // 如果失敗 reject(xhr.status); } } } }) // 指定成功和失敗的回撥 p.then(function(value){ console.log(value); },function(reason){ console.error(reason); }) </script>
這裡藉助 Node.js 方法進行讀取檔案,不瞭解Node.js的方法可以關注我,後期會出相關專欄。
// 1.引入 fs 模組 const fs = require('fs') // 2.呼叫方法讀取檔案 // fs.readFile('./index.md',(err,data)=>{ // // 如果失敗,則丟擲錯誤 // if(err) throw err; // // 如果沒有出錯,則輸出內容 // console.log(data.toString()); // }) // 3.使用 Promise 封裝 const p = new Promise(function(resolve,reject){ fs.readFile('./index.md',(err,data)=>{ // 判斷如果失敗 if(err) reject(err) // 如果成功 resolve(data) }) }) p.then(function(value){ console.log(value.toString()); },function(reason){ console.log("讀取失敗!!"); })
Promise範例具有then方法,即then方法定義在原型物件Promise.prototype上,作用是為Promise範例新增狀態改變時的回撥函數。案例如下:
<script> // 建立 promise 兌現 const p = new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('使用者資料') // reject('出錯啦') }) }) // 呼叫 then 方法 const result = p.then(value =>{ // 如果回撥函數中返回的結果是非 promise 型別屬性,狀態為成功,返回值為物件的成功的值 console.log(value); // 1、非promise型別的屬性 // return 123 // 2、是promise物件 // return new Promise((resolve,reject)=>{ // // resolve('ok') // // reject('error') // }) // 3、丟擲錯誤 throw new Error('出錯啦!!') },reason=>{ console.log(reason); }) // then方法的返回結果是 Promise 物件,物件狀態由回撥函數的執行結果決定 console.log(result); </script>
then方法返回的是一個新的Promise範例,因此可以採用鏈式寫法,即then方法後面再呼叫另一個then方法。但是前一個then()方法中的回撥函數中又可能返回一個Promise範例,這時候後面一個then()方法中的回撥函數會等前一個Promise範例狀態發生變化才會呼叫。案例如下:
<script> let p = new Promise((resolve, reject) => { setTimeout(()=>{ resolve('success') }); },1000); p.then( res => { console.log(res); return `${res} again`; } ) .then( res => console.log(res) ); </script>
回撥地獄與Promise物件實現相比,不會產生回撥現象,而且也不用再資料龐大時進行大規模的縮排。承接上文單檔案讀取,現在進行多檔案讀取,案例如下:
// 1.引入 fs 模組 const { rejects } = require('assert') const fs = require('fs') const { resolve } = require('path') // 2.回撥地獄 呼叫方法讀取檔案 // fs.readFile('./index.md',(err,data)=>{ // fs.readFile('./index1.md',(err,data1)=>{ // fs.readFile('./index2.md',(err,data2)=>{ // let result = data + 'rn' + data1 +'rn'+ data2 // console.log(result); // }) // }) // }) // 3.使用 Promise 實現 const p = new Promise((resolve,reject)=>{ fs.readFile('./index.md',(err,data)=>{ resolve(data) }) }) // value 是第一個檔案的內容 p.then(value => { return new Promise((resolve,reject)=>{ fs.readFile('./index1.md',(err,data)=>{//data是第二個檔案的內容 // 返回的是第一個和第二個檔案合併的陣列 resolve([value, data]) }) }) }).then(value => {//這裡的value就是上面合併的陣列 return new Promise((resolve,reject)=>{ fs.readFile('./index2.md',(err,data)=>{//data是第三個檔案的內容 // 壓入 value.push(data) resolve(value) }) }) }).then(value => {//如果上面成功,現在的value就是返回三個陣列的合集 console.log(value.join('rn'));//陣列用join進行拼接 })
該方法用於指定發生錯誤時的回撥函數。舉個簡單的例子:
<script> const p = new Promise((resolve,reject)=>{ setTimeout(function(){ reject('出錯了!') },1000) }) // p.then(value=>{},reason=>{ // console.log(reason); // }) p.catch(reason=>{ console.log(reason); }) </script>
finally()方法指定不管promise最後的狀態如何,在執行完then或catch指定的回撥函數以後,都會執行finally方法指定的回撥函數。
<script> const p = new Promise((resolve,reject)=>{ setTimeout(function(){ reject('出錯了!') },1000) }) p.catch(reason=>{ console.log(reason); }).finally(()=>{ console.log('我是finall,不管promise結果如何我都要執行'); }) </script>
該方法用於將多個 Promise 範例包裝成一個新的 Promise 範例,方法接受一個陣列作為引數,陣列引數都是Promsie範例。當然引數也可以不是陣列,但必須有Iterator介面,且返回的每個成員都是Promise範例。
該方法只適合所有非同步都操作成功的情況,如果有一個操作失敗就無法滿足要求。
<script> // Promise.all()的狀態由引數決定:分以下兩種情況 /* * (1)Promise.all()引數的狀態都變成fulfilled,Promise.all()狀態才會變成fulfilled,此時所有引數的返回值組成一個陣列,傳遞給Promise.all()的回撥函數。 * (2)只要引數之中有一個被rejected,Promise.all()的狀態就變成rejected,此時第一個被reject的範例的返回值,會傳遞給p的回撥函數。 */ const p1 = new Promise((resolve, reject) => { resolve('hello'); }) .then(result => result); const p2 = new Promise((resolve, reject) => { throw new Error('報錯了'); }) .then(result => result); Promise.all([p1, p2]) .then(result => console.log(result)) .catch(e => console.log(e));//Error:報錯了 </script>
該方法同樣是將多個 Promise 範例包裝成一個新的 Promsie 範例,該方法與 Promise.all()方法一樣,區別是該方法中只要引數之中有一個範例率先改變狀態,該方法的範例狀態跟著改變,那個率先改變的 Promise 範例的返回值就傳遞給該方法範例的回撥函數。
<script> const p = Promise.race([ fetch('./index.js'), new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('request timeout')), 5000) }) ]); p.then(console.log).catch(console.error); </script>
上面程式碼中,如果 5 秒之內fetch方法無法返回結果,變數p的狀態就會變成rejected,從而觸發catch方法指定的回撥函數。
該方法用來確定一組非同步是否都結束(不管成功或失敗)。方法接受一個陣列作為引數,只有當引數陣列中所有 Promise物件 都發生變化,返回的 Promise 物件才會發生狀態變更。
<script> const resolved = Promise.resolve(42); const rejected = Promise.reject(-1); const allSettledPromise = Promise.allSettled([resolved, rejected]); allSettledPromise.then(function (results) { console.log(results); }); </script>
回撥函數接受到的引數是陣列results,該陣列的每一個成員都是一個物件,對應傳入Promise.allSettled()的陣列裡面的兩個 Promsie 物件。
Promise.any()和Promise.race()方法很像,唯一區別就是Promise.any()不會因為某個 Promise 變成 rejected 狀態而結束,必須等到所有引數 Promise 變成 rejected 狀態才會結束。
var resolved = Promise.resolve(42); var rejected = Promise.reject(-1); var alsoRejected = Promise.reject(Infinity); Promise.any([resolved, rejected, alsoRejected]).then(function (result) { console.log(result); // 42 }); Promise.any([rejected, alsoRejected]).catch(function (results) { console.log(results instanceof AggregateError); // true console.log(results.errors); // [-1, Infinity] });
該方法能夠將現有物件轉換為 Promise 物件。
Promise.resolve('foo') // 等價於 new Promise(resolve => resolve('foo'))
到此這篇關於JavaScript中的Promise詳解 的文章就介紹到這了,更多相關JS Promise內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45