<dl id="opymh"></dl>

<div id="opymh"></div>
      <div id="opymh"><tr id="opymh"></tr></div>

        <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

        <em id="opymh"></em>

        <em id="opymh"><ol id="opymh"></ol></em>

              頻道欄目
              首頁 > 程序開發 > web前端 > HTML/CSS > 正文
              關于Promise的9個提示
              2019-02-12 11:21:46           
              收藏   我要投稿
              關于 Promise 的 9 個提示

              正如同事所說的那樣,Promise 在工作中表現優異。

              這篇文章會給你一些如何改善與 Promise 之間關系的建議。

              1. 你可以在 .then 里面 return 一個 Promise

              讓我來說明這最重要的一點

              是的!你可以在 .then 里面 return 一個 Promise

              而且,return 的這個 Promise 將在下一個 .then 中自動解析。

              .then(r => {

              return serverStatusPromise(r); // 返回 { statusCode: 200 } 的 Promise

              })

              .then(resp => {

              console.log(resp.statusCode); // 200; 注意自動解析的 promise

              })

              2. 每次執行 .then 的時候都會自動創建一個新的 Promise

              如果熟悉 javascript 的鏈式風格,那么你應該會感到很熟悉。但是對于一個初學者來說,可能就不會了。

              在 Promise 中不論你使用 .then 或者 .catch 都會創建一個新的 Promise。這個 Promise 是剛剛鏈式調用的 Promise 和 剛剛加上的 .then / .catch 的組合。

              讓我們來看一個 :

              var statusProm = fetchServerStatus();

              var promA = statusProm.then(r => (r.statusCode === 200 "good" : "bad"));

              var promB = promA.then(r => (r === "good" "ALL OK" : "NOTOK"));

              var promC = statusProm.then(r => fetchThisAnotherThing());

              上面 Promise 的關系可以在流程圖中清晰的描述出來:

              需要特別注意的是 promA、 promB 和 promC 全部都是不同的但是有關聯的 Promise。

              我喜歡把 .then 想像成一個大型管道,當上游節點出現問題時,水就會停止流向下游。例如,如果 promB 失敗,下游節點不會受到影響,但是如果 statusProm 失敗,那么下游的所有節點都將受到影響,即 rejected。

              3. 對調用者來說,Promise 的 resolved/rejected 狀態是唯一的

              我認為這個是讓 Promise 好好運行的最重要的事情之一。簡單來說,如果在你的應用中 Promise 在很多不同的模塊之間共享,那么當 Promise 返回 resolved/rejected 狀態時,所有的調用者都會收到通知。

              這也意味著沒有人可以改變你的 Promise,所以可以放心的把它傳遞出去。

              function yourFunc() {

              const yourAwesomeProm = makeMeProm();

              yourEvilUncle(yourAwesomeProm); // 無論 Promise 受到了怎樣的影響,它最終都會成功執行

              return yourAwesomeProm.then(r => importantProcessing(r));

              }

              function yourEvilUncle(prom) {

              return prom.then(r => Promise.reject("destroy!!")); // 可能遭受的影響

              }

              通過上面的例子可以看出,Promise 的設計使得自身很難被改變。正如我上面所說的:"保持冷靜,并將 Promise 傳遞下去"。

              4. Promise 構造函數不是解決方案

              我看到很多開發者喜歡用構造函數的風格,他們認為這就是 Promise 的方式。但這卻是一個謊言,實際的原因是構造函數 API 和之前回調函數的 API 相似,而且這樣的習慣很難改變。

              如果你發現自己正在到處使用 Promise 構造函數,那你的做法是錯的!

              要真正的向前邁進一步并且擺脫回調,你需要小心謹慎并且最小程度地使用 Promise 構造函數。

              讓我們看一下使用 Promise 構造函數 的具體情況:

              return new Promise((res, rej) => {

              fs.readFile("/etc/passwd", function(err, data) {

              if (err) return rej(err);

              return res(data);

              });

              });

              Promise 構造函數 應該只在你想要把回調轉換成 Promise 時使用。

              一旦你掌握了這種創建 Promise 的優雅方式,它將會變的非常有吸引力。

              讓我們看一下冗余的 Promise 構造函數。

              錯誤的

              return new Promise((res, rej) => {

              var fetchPromise = fetchSomeData(.....);

              fetchPromise

              .then(data => {

              res(data); // 錯誤!!!

              })

              .catch(err => rej(err))

              })

              正確的

              return fetchSomeData(...); // 正確的!

              用 Promise 構造函數 封裝 Promise 是多余的,并且違背了 Promise 本身的目的。

              高級技巧

              如果你是一個 nodejs 開發者,我建議你可以看一看 util.promisify。這個方法可以幫助你把 node 風格的回調轉換為 Promise。

              const {promisify} = require('util');

              const fs = require('fs');

              const readFileAsync = promisify(fs.readFile);

              readFileAsync('myfile.txt', 'utf-8')

              .then(r => console.log(r))

              .catch(e => console.error(e));

              5. 使用 Promise.resolve

              Javascript 提供了 Promise.resolve 方法,像下面的例子這樣簡潔:

              var similarProm = new Promise(res => res(5));

              // ^^ 等價于

              var prom = Promise.resolve(5);

              它有多種使用情況,我最喜歡的一種是可以把普通的(異步的)js 對象轉化成 Promise。

              // 將同步函數轉換為異步函數

              function foo() {

              return Promise.resolve(5);

              }

              當不確定它是一個 Promise 還是一個普通的值的時候,你也可以做一個安全的封裝。

              function goodProm(maybePromise) {

              return Promise.resolve(maybePromise);

              }

              goodProm(5).then(console.log); // 5

              var sixPromise = fetchMeNumber(6);

              goodProm(sixPromise).then(console.log); // 6

              goodProm(Promise.resolve(Promise.resolve(5))).then(console.log); // 5, 注意,它會自動解析所有的 Promise!

              6.使用 Promise.reject

              Javascript 也提供了 Promise.reject 方法。像下面的例子這樣簡潔:

              var rejProm = new Promise((res, reject) => reject(5));

              rejProm.catch(e => console.log(e)) // 5

              我最喜歡的用法是提前使用 Promise.reject 來拒絕。

              function foo(myVal) {

              if (!mVal) {

              return Promise.reject(new Error('myVal is required'))

              }

              return new Promise((res, rej) => {

              // 從你的大回調到 Promise 的轉換!

              })

              }

              簡單來說,使用 Promise.reject 可以拒絕任何你想要拒絕的 Promise。

              在下面的例子中,我在 .then 里面使用:

              .then(val => {

              if (val != 5) {

              return Promise.reject('Not Good');

              }

              })

              .catch(e => console.log(e)) // 這樣是不好的

              注意:你可以像 Promise.resolve 一樣在 Promise.reject 中傳遞任何值。你經常在失敗的 Promise 中發現 Error 的原因是因為它主要就是用來拋出一個異步錯誤的。

              7. 使用 Promise.all

              Javascript 提供了 Promise.all 方法。像 ... 這樣的簡潔,好吧,我想不出來例子了。

              在偽算法中,Promise.all 可以被概括為:

              接收一個 Promise 數組

              然后同時運行他們

              然后等到他們全部運行完成

              然后 return 一個新的 Promise 數組

              他們其中有一個失敗或者 reject,都可以被捕獲。

              下面的例子展示了所有的 Promise 完成的情況:

              var prom1 = Promise.resolve(5);

              var prom2 = fetchServerStatus(); // 返回 {statusCode: 200} 的 Promise

              Proimise.all([prom1, prom2])

              .then([val1, val2] => { // 注意,這里被解析成一個數組

              console.log(val1); // 5

              console.log(val2.statusCode); // 200

              })

              下面的例子展示了當他們其中一個失敗的情況:

              var prom1 = Promise.reject(5);

              var prom2 = fetchServerStatus(); // 返回 {statusCode: 200} 的 Promise

              Proimise.all([prom1, prom2])

              .then([val1, val2] => {

              console.log(val1);

              console.log(val2.statusCode);

              })

              .catch(e => console.log(e)) // 5, 直接跳轉到 .catch

              注意:Promise.all 是很聰明的!如果其中一個 Promise 失敗了,它不會等到所有的 Promise 完成,而是立即中止!

              8. 不要害怕 reject,也不要在每個 .then 后面加冗余的 .catch

              我們是不是會經常擔心錯誤會在它們之間的某處被吞噬?

              為了克服這個恐懼,這里有一個簡單的小提示:

              讓 reject 來處理上游函數的問題。

              在理想的情況下,reject 方法應該是應用的根源,所有的 reject 都會向下傳遞。

              不要害怕像下面這樣寫

              return fetchSomeData(...);

              現在如果你想要處理函數中 reject 的情況,請決定是解決問題還是繼續 reject。

              解決 reject

              解決 reject 是很簡單的,在 .catch 不論你返回什么內容,都將被假定為已解決的。然而,如果你在 .catch 中返回 Promise.reject,那么這個 Promise 將會是失敗的。

              .then(() => 5.length) // <-- 這里會報錯

              .catch(e => {

              return 5; // <-- 重新使方法正常運行

              })

              .then(r => {

              console.log(r); // 5

              })

              .catch(e => {

              console.error(e); // 這個方法永遠不會被調用 :)

              })

              拒絕一個 reject

              拒絕一個 reject 是簡單的。不需要做任何事情。 就像我剛剛說的,讓它成為其他函數的問題。通常情況下,父函數有比當前函數處理 reject 更好的方法。

              需要記住的重要的一點是,一旦你寫了 catch 方法,就意味著你正在處理這個錯誤。這個和同步 try/catch的工作方式相似。

              如果你確實想要攔截一個 reject:(我強烈建議不要這樣做!)

              .then(() => 5.length) // <-- 這里會報錯

              .catch(e => {

              errorLogger(e); // 做一些錯誤處理

              return Promise.reject(e); // 拒絕它,是的,你可以這么做!

              })

              .then(r => {

              console.log(r); // 這個 .then (或者任何后面的 .then) 將永遠不會被調用,因為我們在上面使用了 reject :)

              })

              .catch(e => {

              console.error(e); //<-- 它變成了這個 catch 方法的問題

              })

              .then(x,y) 和 then(x).catch(x) 之間的分界線

              .then 接收的第二個回調函數參數也可以用來處理錯誤。它和 then(x).catch(x) 看起來很像,但是他們處理錯誤的區別在于他們自身捕獲的錯誤。

              我會用下面的例子來說明這一點:

              .then(function() {

              return Promise.reject(new Error('something wrong happened'));

              }).catch(function(e) {

              console.error(e); // something wrong happened

              });

              .then(function() {

              return Promise.reject(new Error('something wrong happened'));

              }, function(e) { // 這個回調處理來自當前 `.then` 方法之前的錯誤

              console.error(e); // 沒有錯誤被打印出來

              });

              當你想要處理的是來自上游 Promise 而不是剛剛在 .then 里面加上去的錯誤的時候, .then(x,y) 變的很方便。

              提示: 99.9% 的情況使用簡單的 then(x).catch(x) 更好。

              9. 避免 .then 回調地獄

              這個提示是相對簡單的,盡量避免 .then 里包含 .then 或者 .catch。相信我,這比你想象的更容易避免。

              錯誤的

              request(opts)

              .catch(err => {

              if (err.statusCode === 400) {

              return request(opts)

              .then(r => r.text())

              .catch(err2 => console.error(err2))

              }

              })

              正確的

              request(opts)

              .catch(err => {

              if (err.statusCode === 400) {

              return request(opts);

              }

              })

              .then(r => r.text())

              .catch(err => console.erro(err));

              有些時候我們在 .then 里面需要很多變量,那就別無選擇了,只能再創建一個 .then 方法鏈。

              .then(myVal => {

              const promA = foo(myVal);

              const promB = anotherPromMake(myVal);

              return promA

              .then(valA => {

              return promB.then(valB => hungryFunc(valA, valB)); // 很丑陋!

              })

              })

              我推薦使用 ES6 的解構方法混合著 Promise.all 方法就可以解決這個問題。

              .then(myVal => {

              const promA = foo(myVal);

              const promB = anotherPromMake(myVal);

              return Promise.all([prom, anotherProm])

              })

              .then(([valA, valB]) => { // 很好的使用 ES6 解構

              console.log(valA, valB) // 所有解析后的值

              return hungryFunc(valA, valB)

              })

              注意:如果你的 node/瀏覽器/老板/意識允許,還可以使用 async/await 方法來解決這個問題。

              點擊復制鏈接 與好友分享!回本站首頁
              上一篇:JavaScript常用工具方法封裝
              下一篇:webworker的傳值方式以及耗時對比
              相關文章
              圖文推薦
              點擊排行

              關于我們 | 聯系我們 | 廣告服務 | 投資合作 | 版權申明 | 在線幫助 | 網站地圖 | 作品發布 | Vip技術培訓 | 舉報中心

              版權所有: 紅黑聯盟--致力于做實用的IT技術學習網站

              极速飞艇好假
              <dl id="opymh"></dl>

              <div id="opymh"></div>
                  <div id="opymh"><tr id="opymh"></tr></div>

                    <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                    <em id="opymh"></em>

                    <em id="opymh"><ol id="opymh"></ol></em>

                          <dl id="opymh"></dl>

                          <div id="opymh"></div>
                              <div id="opymh"><tr id="opymh"></tr></div>

                                <em id="opymh"><ins id="opymh"><mark id="opymh"></mark></ins></em><sup id="opymh"><menu id="opymh"></menu></sup>

                                <em id="opymh"></em>

                                <em id="opymh"><ol id="opymh"></ol></em>