<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>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                在Promise中你可以將?`then`?和?`catch`?等方法連在一起寫。這非常像DOM或者jQuery中的方法鏈。 一般的方法鏈都通過返回?`this`?將多個方法串聯起來。 > 關于如何創建方法鏈,可以從參考?[方法鏈的創建方法 - 余味(日語博客)](http://taiju.hatenablog.com/entry/20100307/1267962826)?等資料。 另一方面,由于Promise?[每次都會返回一個新的promise對象](http://liubin.github.io/promises-book/#then-return-new-promise)?,所以從表面上看和一般的方法鏈幾乎一模一樣。 在本小節里,我們會在不改變已有采用方法鏈編寫的代碼的外部接口的前提下,學習如何在內部使用Promise進行重寫。 ## 4.7.1\. fs中的方法鏈 我們下面將會以?[Node.js中的fs](http://nodejs.org/api/fs.html)?為例進行說明。 此外,這里的例子我們更重視代碼的易理解性,因此從實際上來說這個例子可能并不算太實用。 fs-method-chain.js ~~~ "use strict"; var fs = require("fs"); function File() { this.lastValue = null; } // Static method for File.prototype.read File.read = function FileRead(filePath) { var file = new File(); return file.read(filePath); }; File.prototype.read = function (filePath) { this.lastValue = fs.readFileSync(filePath, "utf-8"); return this; }; File.prototype.transform = function (fn) { this.lastValue = fn.call(this, this.lastValue); return this; }; File.prototype.write = function (filePath) { this.lastValue = fs.writeFileSync(filePath, this.lastValue); return this; }; module.exports = File; ~~~ 這個模塊可以將類似下面的 read → transform → write 這一系列處理,通過組成一個方法鏈來實現。 ~~~ var File = require("./fs-method-chain"); var inputFilePath = "input.txt", outputFilePath = "output.txt"; File.read(inputFilePath) .transform(function (content) { return ">>" + content; }) .write(outputFilePath); ~~~ `transform`?接收一個方法作為參數,該方法對其輸入參數進行處理。在這個例子里,我們對通過read讀取的數據在前面加上了?`>>`?字符串。 ## 4.7.2\. 基于Promise的fs方法鏈 下面我們就在不改變剛才的[方法鏈](http://liubin.github.io/promises-book/#fs-method-chain.js)對外接口的前提下,采用Promise對內部實現進行重寫。 fs-promise-chain.js ~~~ "use strict"; var fs = require("fs"); function File() { this.promise = Promise.resolve(); } // Static method for File.prototype.read File.read = function (filePath) { var file = new File(); return file.read(filePath); }; File.prototype.then = function (onFulfilled, onRejected) { this.promise = this.promise.then(onFulfilled, onRejected); return this; }; File.prototype["catch"] = function (onRejected) { this.promise = this.promise.catch(onRejected); return this; }; File.prototype.read = function (filePath) { return this.then(function () { return fs.readFileSync(filePath, "utf-8"); }); }; File.prototype.transform = function (fn) { return this.then(fn); }; File.prototype.write = function (filePath) { return this.then(function (data) { return fs.writeFileSync(filePath, data) }); }; module.exports = File; ~~~ 新增加的`then`?和`catch`都可以看做是指向內部保存的promise對象的別名,而其它部分從對外接口的角度來說都沒有改變,使用方法也和原來一樣。 因此,在使用這個模塊的時候我們只需要修改?`require`?的模塊名即可。 ~~~ var File = require("./fs-promise-chain"); var inputFilePath = "input.txt", outputFilePath = "output.txt"; File.read(inputFilePath) .transform(function (content) { return ">>" + content; }) .write(outputFilePath); ~~~ `File.prototype.then`?方法會調用?`this.promise.then`?方法,并將返回的promise對象賦值給了?`this.promise`?變量這個內部promise對象。 這究竟有什么奧妙么?通過以下的偽代碼,我們可以更容易理解這背后發生的事情。 ~~~ var File = require("./fs-promise-chain"); File.read(inputFilePath) .transform(function (content) { return ">>" + content; }) .write(outputFilePath); // => 處理流程類似以下的偽代碼 promise.then(function read(){ return fs.readFileSync(filePath, "utf-8"); }).then(function transform(content) { return ">>" + content; }).then(function write(){ return fs.writeFileSync(filePath, data); }); ~~~ 看到?`promise = promise.then(...)`?這種寫法,會讓人以為`promise`的值會被覆蓋,也許你會想是不是promise的chain被截斷了。 你可以想象為類似?`promise = addPromiseChain(promise, fn);`?這樣的感覺,我們為promise對象**增加**了新的處理,并返回了這個對象,因此即使自己不實現順序處理的話也不會帶來什么問題。 ## 4.7.3\. 兩者的區別 ### 同步和異步 要說[fs-method-chain.js](http://liubin.github.io/promises-book/#fs-method-chain.js)和[Promise版](http://liubin.github.io/promises-book/#fs-promise-chain.js)兩者之間的差別,最大的不同那就要算是同步和異步了。 如果在類似?[fs-method-chain.js](http://liubin.github.io/promises-book/#fs-method-chain.js)?的方法鏈中加入隊列等處理的話,就可以實現幾乎和異步方法鏈同樣的功能,但是實現將會變得非常復雜,所以我們選擇了簡單的同步方法鏈。 Promise版的話如同在?[專欄: Promise只能進行異步處理?](http://liubin.github.io/promises-book/#promise-is-always-async)里介紹過的一樣,只會進行異步操作,因此使用了promise的方法鏈也是異步的。 ### 錯誤處理 雖然[fs-method-chain.js](http://liubin.github.io/promises-book/#fs-method-chain.js)里面并不包含錯誤處理的邏輯, 但是由于是同步操作,因此可以將整段代碼用?`try-catch`?包起來。 在?[Promise版](http://liubin.github.io/promises-book/#fs-promise-chain.js)?提供了指向內部promise對象的`then`?和?`catch`?別名,所以我們可以像其它promise對象一樣使用`catch`來進行錯誤處理。 fs-promise-chain中的錯誤處理 ~~~ var File = require("./fs-promise-chain"); File.read(inputFilePath) .transform(function (content) { return ">>" + content; }) .write(outputFilePath) .catch(function(error){ console.error(error); }); ~~~ 如果你想在[fs-method-chain.js](http://liubin.github.io/promises-book/#fs-method-chain.js)中自己實現異步處理的話,錯誤處理可能會成為比較大的問題;可以說在進行異步處理的時候,還是使用Promise實現起來比較簡單。 ## 4.7.4\. Promise之外的異步處理 如果你很熟悉Node.js的話,那么看到方法鏈的話,你是不是會想起來?[Stream](http://nodejs.org/api/stream.html)?呢。 如果使用?[Stream](http://nodejs.org/api/stream.html)?的話,就可以免去了保存?`this.lastValue`?的麻煩,還能改善處理大文件時候的性能。 另外,使用Stream的話可能會比使用Promise在處理速度上會快些。 使用Stream進行read→transform→write ~~~ readableStream.pipe(transformStream).pipe(writableStream); ~~~ 因此,在異步處理的時候并不是說Promise永遠都是最好的選擇,要根據自己的目的和實際情況選擇合適的實現方式。 > Node.js的Stream是一種基于Event的技術 關于Node.js中Stream的詳細信息可以參考以下網頁。 * [利用Node.js Stream API對數據進行流式處理 - Block Rockin’ Codes](http://jxck.hatenablog.com/entry/20111204/1322966453) * [Stream2基礎](http://www.slideshare.net/shigeki_ohtsu/stream2-kihon) * [關于Node-v0.12新功能](http://www.slideshare.net/shigeki_ohtsu/node-v012tng12) ## 4.7.5\. Promise wrapper 再回到?[fs-method-chain.js](http://liubin.github.io/promises-book/#fs-method-chain.js)?和?[Promise版](http://liubin.github.io/promises-book/#fs-promise-chain.js),這兩種方法相比較內部實現也非常相近,讓人覺得是不是同步版本的代碼可以直接就當做異步方式來使用呢? 由于JavaScript可以向對象動態添加方法,所以從理論上來說應該可以從非Promise版自動生成Promise版的代碼。(當然靜態定義的實現方式容易處理) 盡管?[ES6 Promises](http://liubin.github.io/promises-book/#es6-promises)?并沒有提供此功能,但是著名的第三方Promise實現類庫?[bluebird](https://github.com/petkaantonov/bluebird/)?等提供了被稱為?[Promisification](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification)?的功能。 如果使用類似這樣的類庫,那么就可以動態給對象增加promise版的方法。 ~~~ var fs = Promise.promisifyAll(require("fs")); fs.readFileAsync("myfile.js", "utf8").then(function(contents){ console.log(contents); }).catch(function(e){ console.error(e.stack); }); ~~~ ### Array的Promise wrapper 前面的?[Promisification](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification)?具體都干了些什么光憑想象恐怕不太容易理解,我們可以通過給原生的?`Array`?增加Promise版的方法為例來進行說明。 在JavaScript中原生DOM或String等也提供了很多創建方法鏈的功能。?`Array`?中就有諸如?`map`?和?`filter`?等方法,這些方法會返回一個數組類型,可以用這些方法方便的組建方法鏈。 array-promise-chain.js ~~~ "use strict"; function ArrayAsPromise(array) { this.array = array; this.promise = Promise.resolve(); } ArrayAsPromise.prototype.then = function (onFulfilled, onRejected) { this.promise = this.promise.then(onFulfilled, onRejected); return this; }; ArrayAsPromise.prototype["catch"] = function (onRejected) { this.promise = this.promise.catch(onRejected); return this; }; Object.getOwnPropertyNames(Array.prototype).forEach(function (methodName) { // Don't overwrite if (typeof ArrayAsPromise[methodName] !== "undefined") { return; } var arrayMethod = Array.prototype[methodName]; if (typeof arrayMethod !== "function") { return; } ArrayAsPromise.prototype[methodName] = function () { var that = this; var args = arguments; this.promise = this.promise.then(function () { that.array = Array.prototype[methodName].apply(that.array, args); return that.array; }); return this; }; }); module.exports = ArrayAsPromise; module.exports.array = function newArrayAsPromise(array) { return new ArrayAsPromise(array); }; ~~~ 原生的 Array 和?`ArrayAsPromise`?在使用時有什么差異呢?我們可以通過對?[上面的代碼](http://liubin.github.io/promises-book/#array-promise-chain.js)?進行測試來了解它們之間的不同點。 array-promise-chain-test.js ~~~ "use strict"; var assert = require("power-assert"); var ArrayAsPromise = require("../src/promise-chain/array-promise-chain"); describe("array-promise-chain", function () { function isEven(value) { return value % 2 === 0; } function double(value) { return value * 2; } beforeEach(function () { this.array = [1, 2, 3, 4, 5]; }); describe("Native array", function () { it("can method chain", function () { var result = this.array.filter(isEven).map(double); assert.deepEqual(result, [4, 8]); }); }); describe("ArrayAsPromise", function () { it("can promise chain", function (done) { var array = new ArrayAsPromise(this.array); array.filter(isEven).map(double).then(function (value) { assert.deepEqual(value, [4, 8]); }).then(done, done); }); }); }); ~~~ 我們看到,在?`ArrayAsPromise`?中也能使用 Array的方法。而且也和前面的例子類似,原生的Array是同步處理,而?`ArrayAsPromise`?則是異步處理,這也是它們的不同之處。 仔細看一下?`ArrayAsPromise`?的實現,也許你已經注意到了,?`Array.prototype`?的所有方法都被實現了。 但是,`Array.prototype`?中也存在著類似`array.indexOf`?等并不會返回數組類型數據的方法,這些方法如果也要支持方法鏈的話就有些不自然了。 在這里非常重要的一點是,我們可以通過這種方式,為具有接收相同類型數據接口的API動態的創建Promise版的API。 如果我們能意識到這種API的規則性的話,那么就可能發現一些新的使用方法。 > 前面我們看到的?[Promisification](https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification)?方法,借鑒了了 Node.js的Core模塊中在進行異步處理時將?`function(error,result){}`方法的第一個參數設為?`error`?這一規則,自動的創建由Promise包裝好的方法。 ## 4.7.6\. 總結 在本小節我們主要學習了下面的這些內容。 * Promise版的方法鏈實現 * Promise并不是總是異步編程的最佳選擇 * Promisification * 統一接口的重用 [ES6 Promises](http://liubin.github.io/promises-book/#es6-promises)只提供了一些Core級別的功能。 因此,我們也許需要對現有的方法用Promise方式重新包裝一下。 但是,類似Event等調用次數沒有限制的回調函數等在并不適合使用Promise,Promise也不能說什么時候都是最好的選擇。 至于什么情況下應該使用Promise,什么時候不該使用Promise,并不是本書要討論的目的, 我們需要牢記的是不要什么都用Promise去實現,我想最好根據自己的具體目的和情況,來考慮是應該使用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>

                              哎呀哎呀视频在线观看