<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                在?[第二章的Promise.resolve](http://liubin.github.io/promises-book/#ch2-promise-resolve)?中我們已經說過,?`Promise.resolve`?的最大特征之一就是可以將thenable的對象轉換為promise對象。 在本小節里,我們將學習一下利用將thenable對象轉換為promise對象這個功能都能具體做些什么事情。 ## 4.2.1\. 將Web Notifications轉換為thenable對象 這里我們以桌面通知 API?[Web Notifications](https://developer.mozilla.org/ja/docs/Web/API/notification)?為例進行說明。 關于Web Notifications API的詳細信息可以參考下面的網址。 * [使用 Web Notifications - WebAPI | MDN](https://developer.mozilla.org/zh-TW/docs/WebAPI/Using_Web_Notifications) * [Can I use Web Notifications](http://caniuse.com/notifications) 簡單來說,Web Notifications API就是能像以下代碼那樣通過?`new Notification`?來顯示通知消息。 ~~~ new Notification("Hi!"); ~~~ 當然,為了顯示通知消息,我們需要在運行?`new Notification`?之前,先獲得用戶的許可。 ![確認是否允許Notification的對話框](https://box.kancloud.cn/2015-07-20_55ac7a3248291.png) Figure 11\. 確認是否允許Notification的對話框 用戶在這個是否允許Notification的對話框選擇后的結果,會通過?`Notification.permission`?傳給我們的程序,它的值可能是允許("granted")或拒絕("denied")這二者之一。 > 是否允許Notification對話框中的可選項,在Firefox中除了允許、拒絕之外,還增加了?_永久有效_?和?_會話范圍內有效_?兩種額外選項,當然?`Notification.permission`?的值都是一樣的。 在程序中可以通過?`Notification.requestPermission()`?來彈出是否允許Notification對話框, 用戶選擇的結果會通過?`status`?參數傳給回調函數。 從這個回調函數我們也可以看出來,用戶選擇允許還是拒絕通知是異步進行的。 ~~~ Notification.requestPermission(function (status) { // status的值為 "granted" 或 "denied" console.log(status); }); ~~~ 到用戶收到并顯示通知為止,整體的處理流程如下所示。 * 顯示是否允許通知的對話框,并異步處理用戶選擇結果 * 如果用戶允許的話,則通過?`new Notification`?顯示通知消息。這又分兩種情況 * 用戶之前已經允許過 * 當場彈出是否允許桌面通知對話框 * 當用戶不允許的時候,不執行任何操作 雖然上面說到了幾種情景,但是最終結果就是用戶允許或者拒絕,可以總結為如下兩種模式。 允許時("granted") 使用?`new Notification`?創建通知消息 拒絕時("denied") 沒有任何操作 這兩種模式是不是覺得有在哪里看過的感覺? 呵呵,用戶的選擇結果,正和在Promise中promise對象變為 Fulfilled 或 Rejected 狀態非常類似。 resolve(成功)時 == 用戶允許("granted") 調用?`onFulfilled`?方法 reject(失敗)時 == 用戶拒絕("denied") 調用?`onRejected`?函數 是不是我們可以用Promise的方式去編寫桌面通知的代碼呢?我們先從回調函數風格的代碼入手看看到底怎么去做。 ## 4.2.2\. Web Notification 包裝函數(wrapper) 首先,我們以回到函數風格的代碼對上面的Web Notification API包裝函數進行重寫,新代碼如下所示。 notification-callback.js ~~~ function notifyMessage(message, options, callback) { if (Notification && Notification.permission === 'granted') { var notification = new Notification(message, options); callback(null, notification); } else if (Notification.requestPermission) { Notification.requestPermission(function (status) { if (Notification.permission !== status) { Notification.permission = status; } if (status === 'granted') { var notification = new Notification(message, options); callback(null, notification); } else { callback(new Error('user denied')); } }); } else { callback(new Error('doesn\'t support Notification API')); } } // 運行實例 // 第二個參數是傳給 `Notification` 的option對象 notifyMessage("Hi!", {}, function (error, notification) { if(error){ return console.error(error); } console.log(notification);// 通知對象 }); ~~~ 在回調風格的代碼里,當用戶拒絕接收通知的時候,?`error`?會被設置值,而如果用戶同意接收通知的時候,則會顯示通知消息并且?`notification`?會被設置值。 回調函數接收error和notification兩個參數 ~~~ function callback(error, notification){ } ~~~ 下面,我想再將這個回調函數風格的代碼使用Promise進行改寫。 ## 4.2.3\. Web Notification as Promise 基于上述回調風格的?`notifyMessage`?函數,我們再來創建一個返回promise對象的?`notifyMessageAsPromise`?方法。 notification-as-promise.js ~~~ function notifyMessage(message, options, callback) { if (Notification && Notification.permission === 'granted') { var notification = new Notification(message, options); callback(null, notification); } else if (Notification.requestPermission) { Notification.requestPermission(function (status) { if (Notification.permission !== status) { Notification.permission = status; } if (status === 'granted') { var notification = new Notification(message, options); callback(null, notification); } else { callback(new Error('user denied')); } }); } else { callback(new Error('doesn\'t support Notification API')); } } function notifyMessageAsPromise(message, options) { return new Promise(function (resolve, reject) { notifyMessage(message, options, function (error, notification) { if (error) { reject(error); } else { resolve(notification); } }); }); } // 運行示例 notifyMessageAsPromise("Hi!").then(function (notification) { console.log(notification);// 通知對象 }).catch(function(error){ console.error(error); }); ~~~ 在用戶允許接收通知的時候,運行上面的代碼,會顯示?`"Hi!"`?消息。 當用戶接收通知消息的時候,?`.then`?函數會被調用,當用戶拒絕接收消息的時候,?`.catch`?方法會被調用。 > 由于瀏覽器是以網站為單位保存Web Notifications API的許可狀態的,所以實際上有下面四種模式存在。 > 已經獲得用戶許可 > `.then`?方法被調用 > 彈出詢問對話框并獲得許可 > `.then`?方法被調用 > 已經是被用戶拒絕的狀態 > `.catch`?方法被調用 > 彈出詢問對話框并被用戶拒絕 > `.catch`?方法被調用 > 也就是說,如果使用原生的Web Notifications API的話,那么需要在程序中對上述四種情況都進行處理,我們可以像下面的包裝函數那樣,將上述四種情況簡化為兩種以方便處理。 上面的?[notification-as-promise.js](http://liubin.github.io/promises-book/#notification-as-promise.js)?雖然看上去很方便,但是實際上使用的時候,很可能出現?**在不支持Promise的環境下不能使用**?的問題。 如果你想編寫像[notification-as-promise.js](http://liubin.github.io/promises-book/#notification-as-promise.js)這樣具有Promise風格和的類庫的話,我覺得你有如下的一些選擇。 支持Promise的環境是前提 * 需要最終用戶保證支持`Promise` * 在不支持Promise的環境下不能正常工作(即應該出錯)。 在類庫中實現`Promise` * 在類庫中實現`Promise`功能 * 例如)?[localForage](https://github.com/mozilla/localForage) 在回調函數中也應該能夠使用?`Promise` * 用戶可以選擇合適的使用方式 * 返回Thenable類型 [notification-as-promise.js](http://liubin.github.io/promises-book/#notification-as-promise.js)就是以`Promise`存在為前提的寫法。 回歸正文,在這里[Thenable](http://liubin.github.io/promises-book/#Thenable)是為了幫助實現**在回調函數中也能使用`Promise`**的一個概念。 ## 4.2.4\. Web Notifications As Thenable 我們已經說過,[thenable](http://liubin.github.io/promises-book/#Thenable)就是一個具有?`.then`方法的一個對象。下面我們就在[notification-callback.js](http://liubin.github.io/promises-book/#notification-callback.js)中增加一個返回值為?`thenable`?類型的方法。 notification-thenable.js ~~~ function notifyMessage(message, options, callback) { if (Notification && Notification.permission === 'granted') { var notification = new Notification(message, options); callback(null, notification); } else if (Notification.requestPermission) { Notification.requestPermission(function (status) { if (Notification.permission !== status) { Notification.permission = status; } if (status === 'granted') { var notification = new Notification(message, options); callback(null, notification); } else { callback(new Error('user denied')); } }); } else { callback(new Error('doesn\'t support Notification API')); } } // 返回 `thenable` function notifyMessageAsThenable(message, options) { return { 'then': function (resolve, reject) { notifyMessage(message, options, function (error, notification) { if (error) { reject(error); } else { resolve(notification); } }); } }; } // 運行示例 Promise.resolve(notifyMessageAsThenable("message")).then(function (notification) { console.log(notification);// 通知對象 }).catch(function(error){ console.error(error); }); ~~~ [notification-thenable.js](http://liubin.github.io/promises-book/#notification-thenable.js)里增加了一個?`notifyMessageAsThenable`方法。這個方法返回的對象具備一個`then`方法。 `then`方法的參數和?`new Promise(function (resolve, reject){})`?一樣,在確定時執行?`resolve`?方法,拒絕時調用?`reject`?方法。 `then`?方法和?[notification-as-promise.js](http://liubin.github.io/promises-book/#notification-as-promise.js)?中的?`notifyMessageAsPromise`?方法完成了同樣的工作。 我們可以看出,?`Promise.resolve(thenable)`?通過使用了?`thenable`?這個promise對象,就能利用Promise功能了。 ~~~ Promise.resolve(notifyMessageAsThenable("message")).then(function (notification) { console.log(notification);// 通知對象 }).catch(function(error){ console.error(error); }); ~~~ 使用了Thenable的[notification-thenable.js](http://liubin.github.io/promises-book/#notification-thenable.js)?和依賴于Promise的?[notification-as-promise.js](http://liubin.github.io/promises-book/#notification-as-promise.js)?,實際上都是非常相似的使用方法。 [notification-thenable.js](http://liubin.github.io/promises-book/#notification-thenable.js)?和?[notification-as-promise.js](http://liubin.github.io/promises-book/#notification-as-promise.js)比起來,有以下的不同點。 * 類庫側沒有提供?`Promise`?的實現 * 用戶通過?`Promise.resolve(thenable)`?來自己實現了?`Promise` * 作為Promise使用的時候,需要和?`Promise.resolve(thenable)`?一起配合使用 通過使用[Thenable](http://liubin.github.io/promises-book/#Thenable)對象,我們可以實現類似已有的回調式風格和Promise風格中間的一種實現風格。 ## 4.2.5\. 總結 在本小節我們主要學習了什么是Thenable,以及如何通過`Promise.resolve(thenable)`?使用Thenable,將其作為promise對象來使用。 Callback?—?Thenable?—?Promise Thenable風格表現為位于回調和Promise風格中間的一種狀態,作為類庫的公開API有點不太成熟,所以并不常見。 Thenable本身并不依賴于`Promise`功能,但是Promise之外也沒有使用Thenable的方式,所以可以認為Thenable間接依賴于Promise。 另外,用戶需要對?`Promise.resolve(thenable)`?有所理解才能使用好Thenable,因此作為類庫的公開API有一部分會比較難。和公開API相比,更多情況下是在內部使用Thenable。 > 在編寫異步處理的類庫的時候,推薦采用先編寫回調風格的函數,然后再轉換為公開API這種方式。 > 貌似Node.js的Core module就采用了這種方式,除了類庫提供的基本回調風格的函數之外,用戶也可以通過Promise或者Generator等自己擅長的方式進行實現。 > 最初就是以能被Promise使用為目的的類庫,或者其本身依賴于Promise等情況下,我想將返回promise對象的函數作為公開API應該也沒什么問題。 ### 什么時候該使用Thenable? 那么,又是在什么情況下應該使用Thenable呢? 恐怕最可能被使用的是在?[Promise類庫](http://liubin.github.io/promises-book/#promise-library)?之間進行相互轉換了。 比如,類庫Q的Promise實例為Q promise對象,提供了?[ES6 Promises](http://liubin.github.io/promises-book/#es6-promises)?的promise對象不具備的方法。Q promise對象提供了?`promise.finally(callback)`?和?`promise.nodeify(callback)`?等方法。 如果你想將ES6 Promises的promise對象轉換為Q promise的對象,輪到Thenable大顯身手的時候就到了。 使用thenable將promise對象轉換為Q promise對象 ~~~ var Q = require("Q"); // 這是一個ES6的promise對象 var promise = new Promise(function(resolve){ resolve(1); }); // 變換為Q promise對象 Q(promise).then(function(value){ console.log(value); }).finally(function(){ //因為是Q promise對象所以可以使用?`finally`?方法 console.log("finally"); }); ~~~ 上面代碼中最開始被創建的promise對象具備`then`方法,因此是一個Thenable對象。我們可以通過`Q(thenable)`方法,將這個Thenable對象轉換為Q promise對象。 可以說它的機制和?`Promise.resolve(thenable)`?一樣,當然反過來也一樣。 像這樣,Promise類庫雖然都有自己類型的promise對象,但是它們之間可以通過Thenable這個共通概念,在類庫之間(當然也包括native Promise)進行promise對象的相互轉換。 我們看到,就像上面那樣,Thenable多在類庫內部實現中使用,所以從外部來說不會經常看到Thenable的使用。但是我們必須牢記Thenable是Promise中一個非常重要的概念。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看