成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JavaScript 異步編程指南 — Give me a Promise

開發(fā) 前端
Promise 是一個(gè)對(duì)象用來表示異步操作的結(jié)果,我們沒有辦法同步的知道它的結(jié)果,但是這個(gè)結(jié)果可以用來表示未來值,將來的某個(gè)時(shí)間點(diǎn)我們可以拿到該值,它可能成功,也可能失敗,也會(huì)一直等待下去(這個(gè)請(qǐng)看下文 “無法取消的承諾”)。

[[403926]]

本文轉(zhuǎn)載自微信公眾號(hào)「五月君」,作者五月君。轉(zhuǎn)載本文請(qǐng)聯(lián)系五月君公眾號(hào)。

“Give me a promise, I will not go anywhere, just stand here and wait for you.”

“給我一個(gè)承諾,我哪里都不會(huì)去,就在原地等你。” 這句話形式 Promise 還挺有意思的,文中我會(huì)在提及!

隨著 ES6 標(biāo)準(zhǔn)的出現(xiàn),給我們帶來了一個(gè)新的異步解決方案 Promise。目前絕大多數(shù) JavaScript 新增的異步 API 無論是在瀏覽器端還是 Node.js 服務(wù)端都是基于 Promise 構(gòu)建的,以前基于 Callback 形式的也有解決方案將其轉(zhuǎn)為 Promise。

看過筆者上一節(jié)對(duì) “Promise 前世 Deferred 的講解”,對(duì)于本章學(xué)習(xí)相對(duì)會(huì)更輕松一些,開始前我們還是先了解下 Promise/A+ 規(guī)范,更好的理解下 Promise 的一些思想和規(guī)則。

了解下 Promise 是什么?

Promise 是一個(gè)對(duì)象用來表示異步操作的結(jié)果,我們沒有辦法同步的知道它的結(jié)果,但是這個(gè)結(jié)果可以用來表示未來值,將來的某個(gè)時(shí)間點(diǎn)我們可以拿到該值,它可能成功,也可能失敗,也會(huì)一直等待下去(這個(gè)請(qǐng)看下文 “無法取消的承諾”)。

在 Promise A+ 規(guī)范中有一些專業(yè)的術(shù)語,先了解下:

  • fulfill:Promise 在成功時(shí)的一個(gè)結(jié)果,表示解決,在很多的 Promise 實(shí)現(xiàn)中會(huì)使用 resolve 代替,這是一個(gè)意思,通常在 resolve 里我們接收程序的正確響應(yīng)。
  • reject:Promise 在失敗時(shí)的一個(gè)結(jié)果,通常在 reject 里我們接收一個(gè)錯(cuò)誤信息。
  • eventual value:代表終值,這是 Promise 被解決時(shí)傳遞給解決回調(diào)的值,例如 resolve(value) 這時(shí) Promise 狀態(tài)就會(huì)結(jié)束進(jìn)入 fulfill。
  • reason:拒因,指 Promise 在被拒絕時(shí)傳遞給拒絕回調(diào)的值,例如 reject(reason) 這時(shí) Promise 狀態(tài)結(jié)束進(jìn)入 reject。

這些概念在我們想要更深入的了解 Promise 是需要的,例如,我們實(shí)現(xiàn)一個(gè)自己的 Promise 最好也是按照這種規(guī)范去做,本節(jié)我們主要將 Promise 的基礎(chǔ)使用,后面也會(huì)在異步進(jìn)階里去講 Promise 的實(shí)現(xiàn)原理,實(shí)現(xiàn)一個(gè)自己的 Promise 對(duì)象。

Promise 狀態(tài)流轉(zhuǎn)

一個(gè) Promise 在被創(chuàng)建出來時(shí)是一個(gè)等待態(tài),最后要么成功、要么失敗這個(gè)狀態(tài)是不能夠逆轉(zhuǎn)的:

  • 等待態(tài)(Pending)
  • 執(zhí)行態(tài)(Fulfilled)
  • 拒絕態(tài)(Rejected)

這幾個(gè)狀態(tài)流轉(zhuǎn)就像一個(gè)狀態(tài)機(jī),通過這個(gè)圖也可看到狀態(tài)只能從 Pending -> Fulfilled 或 Pending -> Rejected

將一個(gè) Callback 改造為 Promise

目前有些 API 直接是基于 Promise 的形式,例如 Fetch API 從網(wǎng)絡(luò)獲取數(shù)據(jù)。

  1. fetch('http://example.com/movies.json'
  2.   .then(function(response) { 
  3.     // TODO 
  4.   }); 

舉一個(gè) Node.js 的示例,例如 fs.readFile() 這個(gè) API 默認(rèn)是 callback 的形式,如果要轉(zhuǎn)為 Promise 也很方便。

  1. fs.readFile('xxx'function(err, result) { 
  2.   console.error('Error: ', err);  
  3.   console.log('Result: ', result); 
  4. }); 

方式一:new Promise 實(shí)現(xiàn)

new Promise() 是創(chuàng)建一個(gè)新的 Promise 對(duì)象,之后我們可以在里面使用 resolve、reject 返回結(jié)果信息。

  1. const readFile = filename => new Promise((resolve, reject) => { 
  2.  fs.readFile(filename, (err, file) => { 
  3.    if (err) { 
  4.      reject(err); 
  5.     } else { 
  6.      resolve(file); 
  7.     } 
  8.   }) 
  9. }); 
  10.  
  11. readFile('xxx'
  12.  .then(result => console.log(result)) 
  13.   .catch(err => console.log(err)); 

方式二:Node.js util.promisify 工具

Node.js util 模塊提供了很多工具函數(shù)。為了解決回調(diào)地獄問題,Nodejs v8.0.0 提供了 promisify 方法可以將 Callback 轉(zhuǎn)為 Promise 對(duì)象。筆者之前也曾寫過一篇解析 “Node.js 源碼解析 util.promisify 如何將 Callback 轉(zhuǎn)為 Promise”

  1. const { promisify } = require('util'); 
  2. const readFilePromisify = util.promisify(fs.readFile); // 轉(zhuǎn)為 Promise 
  3.  
  4. readFilePromisify('xxx'
  5.   .then(result => console.log(result)) 
  6.   .catch(err => console.log(err)); 

除此之外 Node.js fs 模塊的 fs.promises API 提供了一組備用的異步文件系統(tǒng)的方法,它們返回 Promise 對(duì)象而不是使用回調(diào)。API 可通過 require('fs').promises 或 require('fs/promises') 訪問。

  1. const fsPromises = require('fs/promises'); 
  2. fsPromises('xxx'
  3.   .then(result => console.log(result)) 
  4.   .catch(err => console.log(err)); 

Promise 錯(cuò)誤管理

Promise 實(shí)例提供了兩種錯(cuò)誤捕獲的方式:一是 Promise.then() 方法傳入第二個(gè)參數(shù),另一種是 Promise 實(shí)例的 catch() 方法。

  • .then() 第二個(gè)回調(diào)參數(shù)捕獲錯(cuò)誤具有就近的原則,不會(huì)影響后續(xù) then 的進(jìn)行。
  • Promise 拋錯(cuò)具有冒泡機(jī)制,能夠不斷傳遞,可以使用 catch() 統(tǒng)一處理。
  1. const ajax = function(){ 
  2.   console.log('promise 開始執(zhí)行'); 
  3.   return new Promise(function(resolve,reject){ 
  4.     setTimeout(function(){ 
  5.       reject(`There's a mistake`); 
  6.     },1000); 
  7.   }); 
  8.  
  9. ajax() 
  10.   .then(function(){ 
  11.     console.log('then1'); 
  12.     return Promise.resolve(); 
  13.   }, err => { 
  14.     console.log('then1里面捕獲的err: ', err); 
  15.   }) 
  16.   .then(function(){ 
  17.     console.log('then2'); 
  18.     return Promise.reject(`There's a then mistake`); 
  19.   }) 
  20.   .catch(err => { 
  21.     console.log('catch里面捕獲的err: ', err); 
  22.   }); 
  23.  
  24. // 輸出 
  25. // promise開始執(zhí)行 
  26. // then1里面捕獲的err:  There's a mistake 
  27. // then2 
  28. // catch里面捕獲的err:  There's a then mistake 

Promise 幾個(gè)方法

Promise.all() 并行執(zhí)行

Promise.all() 以數(shù)組的形式接收多個(gè) Promise 實(shí)例,內(nèi)部好比一個(gè) for 循環(huán)執(zhí)行傳入的多個(gè) Promise 實(shí)例,當(dāng)所有結(jié)果都成功之后返回結(jié)果,執(zhí)行過程中一旦其中某個(gè) Promise 實(shí)例發(fā)生 reject 就會(huì)觸發(fā) Promise.all() 的 catch() 函數(shù)。以下示例,加載 3 張圖片,如果全部成功之后渲染結(jié)果到頁面中。

  1. function loadImg(src){ 
  2.   return new Promise((resolve,reject) => { 
  3.     let img = document.createElement('img'); 
  4.     img.src = src; 
  5.     img.onload = () => { 
  6.       resolve(img); 
  7.     } 
  8.     img.onerror = (err) => { 
  9.       reject(err) 
  10.     } 
  11.   }) 
  12. function showImgs(imgs){ 
  13.   imgs.forEach(function(img){ 
  14.     document.body.appendChild(img) 
  15.   }) 
  16. Promise.all([ 
  17.   loadImg('http://www.xxxxxx.com/uploads/1.jpg'), 
  18.   loadImg('http://www.xxxxxx.com/uploads/2.jpg'), 
  19.   loadImg('http://www.xxxxxx.com/uploads/3.jpg'
  20. ]).then(showImgs) 

在 Promise 鏈?zhǔn)秸{(diào)用中,任意時(shí)刻都只有一個(gè)任務(wù)執(zhí)行,下一個(gè)任務(wù)要等待這個(gè)任務(wù)完成之后才能執(zhí)行,如果現(xiàn)在我有兩個(gè)或以上的任務(wù),之間沒有順序依賴關(guān)系,希望它們能夠并行執(zhí)行,這樣可以提高效率,此時(shí)就可以選擇 Promise.all()。

Promise.race() 率先執(zhí)行

Promise.race() 只要其中一個(gè) Promise 實(shí)例率先發(fā)生改變,其它的將不在響應(yīng)。好比短跑比賽,我只想知道第一是誰,當(dāng)?shù)谝粋€(gè)人跨越終點(diǎn)線之后,我的目的就達(dá)到了。還是基于上面的示例,只要有一個(gè)圖片加載完成就直接添加到頁面。

  1. function showImgs(img){ 
  2.   let p = document.createElement('p'); 
  3.   p.appendChild(img); 
  4.   document.body.appendChild(p); 
  5.  
  6. Promise.race([ 
  7.   loadImg('http://www.xxxxxx.com/uploads/1.jpg'), 
  8.   loadImg('http://www.xxxxxx.com/uploads/2.jpg'), 
  9.   loadImg('http://www.xxxxxx.com/uploads/3.jpg'
  10. ]).then(showImgs) 

Promise.finally()

Promise 在執(zhí)行后最終結(jié)果要么成功進(jìn)入 then,要么失敗 進(jìn)入 catch。也許某些時(shí)候我們需要一個(gè)總是能夠被調(diào)用的回調(diào),以便做一些清理工作,ES7 新加入了 finally 也許是你不錯(cuò)的選擇。

Promise.finally() 在 Node.js 10.3.0 版本之后支持。

  1. const p = Promise.resolve(); 
  2.  .then(onSuccess) 
  3.  .catch(onFailed) 
  4.  .finally(cleanup); 

Promise.any()

Promise.any() 接收一個(gè)數(shù)組作為參數(shù),可傳入多個(gè) Promise 實(shí)例,只要其中一個(gè) Promise 變?yōu)?Fulfilled 狀態(tài),就返回該 Promise 實(shí)例,只有全部 Promise 實(shí)例都變?yōu)?Rejected 拒絕態(tài),Promise.any() 才會(huì)返回 Rejected。Promise.any() 在 Node.js 15.14.0 版本之后支持。

  1. Promise.any([ 
  2.   Promise.reject('FAILED'), 
  3.   Promise.resolve('SUCCESS1'), 
  4.   Promise.resolve('SUCCESS2'),  
  5. ]).then(result => { 
  6.   console.log(result); // SUCCESS1 
  7. }); 

Promise.allSettled()

Promise.allSettled() 與 Promise.all() 類似,不同的是 Promise.allSettled() 執(zhí)行完成不會(huì)失敗,它會(huì)將所有的結(jié)果以數(shù)組的形式返回,我們可以拿到每個(gè) Promise 實(shí)例的執(zhí)行狀態(tài)和結(jié)果。

Promise.allSettled() 在 Node.js 12.10.0 版本之后支持。

  1. Promise.allSettled([ 
  2.   Promise.reject('FAILED'), 
  3.   Promise.resolve('SUCCESS1'), 
  4.   Promise.resolve('SUCCESS2'),  
  5. ]).then(results => { 
  6.   console.log(results); 
  7. }); 
  8.  
  9. // [ 
  10. //   { status: 'rejected', reason: 'FAILED' }, 
  11. //   { status: 'fulfilled', value: 'SUCCESS1' }, 
  12. //   { status: 'fulfilled', value: 'SUCCESS2' } 
  13. // ] 

無法取消的承諾

剛開始引用了一句話 “Give me a promise, I will not go anywhere, just stand here and wait for you.” 就好比一個(gè)小伙子對(duì)一個(gè)心儀的姑娘說:“給我一個(gè)承諾,我哪里都不會(huì)去,就在原地等你”。

好比我們的程序,創(chuàng)建了一個(gè) Promise 對(duì)象 promise,并為其注冊(cè)了完成和拒絕的處理函數(shù),因?yàn)橐恍┰颍覀儧]有給予它 resolve/reject,這個(gè)時(shí)候 promise 對(duì)象將會(huì)一直處于 Pending 等待狀態(tài)。我們也無法從外部取消。如果 then 后面還有業(yè)務(wù)需要處理,也將會(huì)一直等待下去,當(dāng)我們自己去包裝一個(gè) Promise 對(duì)象時(shí)要盡可能的避免這種情況發(fā)生。

  1. const promise = new Promise((resolve, reject) => { 
  2.   // 沒有 resolve 也沒有 reject 
  3. }); 
  4.  
  5. console.log(promise); // Promise {<pending>} 
  6. promise 
  7.   .then(() => { 
  8.     console.log('resolve'); 
  9.   }).catch(err => { 
  10.     console.log('reject');          
  11.   }); 

使用 Promise 改造 Callback 回調(diào)地獄示例

這是我們之前在講解 JavaScript 異步編程指南 Callback 一節(jié)寫的例子:

  1. fs.readdir('/path/xxxx', (err, files) => { 
  2.   if (err) { 
  3.     // TODO... 
  4.   } 
  5.   files.forEach((filename, index) => { 
  6.     fs.lstat(filename, (err, stats) => { 
  7.       if (err) { 
  8.         // TODO... 
  9.       } 
  10.       if (stats.isFile()) { 
  11.         fs.readFile(filename, (err, file) => { 
  12.           // TODO 
  13.         }) 
  14.       } 
  15.     }) 
  16.   }) 
  17. }); 

Node.js 的 fs 模塊為我們提供了 promises 對(duì)象,現(xiàn)在解決了深層次嵌套問題,這個(gè)問題還有更優(yōu)雅的寫法,在之后的 Async/Await 章節(jié)我們會(huì)繼續(xù)介紹。

  1. const fs = require('fs').promises; 
  2. const path = require('path'); 
  3. const rootDir = '/path/xxxx'
  4. fs.readdir('/path/xxxx'
  5.  .then(files => { 
  6.   files.forEach(checkFileAndRead); 
  7.   }) 
  8.   .catch(err => { 
  9.     // TODO 
  10.   }); 
  11.  
  12. function checkFileAndRead(filename, index) { 
  13.   const file = path.resolve(rootDir, filename); 
  14.   return fs.lstat(file) 
  15.     .then(stats => { 
  16.       if (stats.isFile()) { 
  17.         return fs.readFile(file); 
  18.       } 
  19.     }) 
  20.     .then(chunk => { 
  21.       // TODO 
  22.     }) 
  23.     .catch(err => { 
  24.       // TODO 
  25.     }) 

總結(jié)

 

Promise 是很好的,它解決了 callback 形式的回調(diào)地獄、難以管理的錯(cuò)誤處理問題, Promise 提供了一種鏈?zhǔn)降囊跃€性的方式(.then().then().then()...)來管理我們的異步代碼,這種方式是可以的,解決了我們一些問題,但是并非完美,在 Async/Await 章節(jié)你會(huì)看到關(guān)于異步編程問題更好的解決方案,但是 Promise 是基礎(chǔ),請(qǐng)掌握它。以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系麒思妙想公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 五月君
相關(guān)推薦

2019-06-11 18:06:32

智能

2017-05-11 20:20:59

JavascriptPromiseWeb

2020-10-15 13:29:57

javascript

2021-06-28 08:10:59

JavaScript異步編程

2023-01-12 11:23:11

Promise異步編程

2021-11-01 22:36:04

JavaScript

2015-04-22 10:50:18

JavascriptJavascript異

2014-05-23 10:12:20

Javascript異步編程

2017-07-13 12:12:19

前端JavaScript異步編程

2016-09-07 20:43:36

Javascript異步編程

2017-01-12 14:55:50

JavaScript編程

2025-03-07 07:20:00

JavaScript異步編程Promise

2021-06-02 09:01:19

JavaScript 前端異步編程

2018-11-29 08:00:20

JavaScript異步Promise

2020-03-29 08:27:05

Promise異步編程前端

2011-11-11 15:47:22

JavaScript

2021-10-22 08:29:14

JavaScript事件循環(huán)

2021-06-15 07:10:14

JavaScript異步編程

2021-12-10 07:47:30

Javascript異步編程

2023-09-15 15:31:23

異步編程Promise
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 成人动漫视频网站 | 日韩在线 | 欧美精品一二三 | 91在线精品一区二区 | 亚洲国产一区在线 | 午夜精品一区二区三区在线视频 | 成人中文网 | 欧美一区二区三区高清视频 | 午夜精品久久久久久久久久久久 | 亚洲一区二区三区免费观看 | 亚洲精品一区二区三区蜜桃久 | 成人一区二区三区 | 国产精品成人一区二区三区 | 久久av一区二区三区 | 狠狠躁18三区二区一区 | 美女亚洲一区 | 亚洲欧美中文日韩在线v日本 | 超碰在线人 | 日本三级精品 | 国产 日韩 欧美 在线 | 中文字幕av网 | 久久综合久久综合久久综合 | 欧美一区二区免费在线 | 久久6视频 | 国产一在线观看 | 亚洲精品乱码久久久久久蜜桃91 | 夜夜摸天天操 | 91精品国产91久久综合桃花 | 中文字幕在线剧情 | 91久久精 | 四虎首页 | 中文字幕一区二区三 | 欧美在线a | 久久久久久久久久久久久91 | 日日欧美 | 精品一区二区三区四区五区 | 超碰国产在线 | 欧美性大战久久久久久久蜜臀 | 中文av电影 | 亚洲免费在线观看 | 国产国产精品 |