<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 功能強大 支持多語言、二開方便! 廣告
                ## 知識點 1. 理解 Promise 概念,為什么需要 promise 2. 學習 q 的 API,利用 q 來替代回調函數([https://github.com/kriskowal/q](https://github.com/kriskowal/q)?) ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#課程內容)課程內容 第五課講述了如何使用 async 來控制并發。async 的本質是一個流程控制。其實在異步編程中,還有一個更為經典的模型,叫做 Promise/Deferred 模型。 本節我們就來學習這個模型的代表實現:[q](https://github.com/kriskowal/q) 首先,我們思考一個典型的異步編程模型,考慮這樣一個題目:讀取一個文件,在控制臺輸出這個文件內容。 ~~~ var fs = require('fs'); fs.readFile('sample.txt', 'utf8', function (err, data) { console.log(data); }); ~~~ 看起來很簡單,再進一步: 讀取兩個文件,在控制臺輸出這兩個文件內容。 ~~~ var fs = require('fs'); fs.readFile('sample01.txt', 'utf8', function (err, data) { console.log(data); fs.readFile('sample02.txt', 'utf8', function (err,data) { console.log(data); }); }); ~~~ 要是讀取更多的文件呢? ~~~ var fs = require('fs'); fs.readFile('sample01.txt', 'utf8', function (err, data) { fs.readFile('sample02.txt', 'utf8', function (err,data) { fs.readFile('sample03.txt', 'utf8', function (err, data) { fs.readFile('sample04.txt', 'utf8', function (err, data) { }); }); }); }); ~~~ 這段代碼就是臭名昭著的邪惡金字塔(Pyramid of Doom)。可以使用async來改善這段代碼,但是在本課中我們要用promise/defer來改善它。 ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#promise基本概念)promise基本概念 先學習promise的基本概念。 * promise只有三種狀態,未完成,完成(fulfilled)和失敗(rejected)。 * promise的狀態可以由未完成轉換成完成,或者未完成轉換成失敗。 * promise的狀態轉換只發生一次 promise有一個then方法,then方法可以接受3個函數作為參數。前兩個函數對應promise的兩種狀態fulfilled, rejected的回調函數。第三個函數用于處理進度信息。 ~~~ promiseSomething().then(function(fulfilled){ //當promise狀態變成fulfilled時,調用此函數 },function(rejected){ //當promise狀態變成rejected時,調用此函數 },function(progress){ //當返回進度信息時,調用此函數 }); ~~~ 學習一個簡單的例子: ~~~ var Q = require('q'); var defer = Q.defer(); /** * 獲取初始promise * @private */ function getInitialPromise() { return defer.promise; } /** * 為promise設置三種狀態的回調函數 */ getInitialPromise().then(function(success){ console.log(success); },function(error){ console.log(error); },function(progress){ console.log(progress); }); defer.notify('in progress');//控制臺打印in progress defer.resolve('resolve'); //控制臺打印resolve defer.reject('reject'); //沒有輸出。promise的狀態只能改變一次 ~~~ ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#promise的傳遞)promise的傳遞 then方法會返回一個promise,在下面這個例子中,我們用outputPromise指向then返回的promise。 ~~~ var outputPromise = getInputPromise().then(function (fulfilled) { }, function (rejected) { }); ~~~ 現在outputPromise就變成了受?`function(fulfilled)`?或者?`function(rejected)`控制狀態的promise了。怎么理解這句話呢? * 當function(fulfilled)或者function(rejected)返回一個值,比如一個字符串,數組,對象等等,那么outputPromise的狀態就會變成fulfilled。 在下面這個例子中,我們可以看到,當我們把inputPromise的狀態通過defer.resovle()變成fulfilled時,控制臺輸出fulfilled. 當我們把inputPromise的狀態通過defer.reject()變成rejected,控制臺輸出rejected ~~~ var Q = require('q'); var defer = Q.defer(); /** * 通過defer獲得promise * @private */ function getInputPromise() { return defer.promise; } /** * 當inputPromise狀態由未完成變成fulfil時,調用function(fulfilled) * 當inputPromise狀態由未完成變成rejected時,調用function(rejected) * 將then返回的promise賦給outputPromise * function(fulfilled) 和 function(rejected) 通過返回字符串將outputPromise的狀態由 * 未完成改變為fulfilled * @private */ var outputPromise = getInputPromise().then(function(fulfilled){ return 'fulfilled'; },function(rejected){ return 'rejected'; }); /** * 當outputPromise狀態由未完成變成fulfil時,調用function(fulfilled),控制臺打印'fulfilled: fulfilled'。 * 當outputPromise狀態由未完成變成rejected, 調用function(rejected), 控制臺打印'fulfilled: rejected'。 */ outputPromise.then(function(fulfilled){ console.log('fulfilled: ' + fulfilled); },function(rejected){ console.log('rejected: ' + rejected); }); /** * 將inputPromise的狀態由未完成變成rejected */ defer.reject(); //輸出 fulfilled: rejected /** * 將inputPromise的狀態由未完成變成fulfilled */ //defer.resolve(); //輸出 fulfilled: fulfilled ~~~ * 當function(fulfilled)或者function(rejected)拋出異常時,那么outputPromise的狀態就會變成rejected ~~~ var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通過defer獲得promise * @private */ function getInputPromise() { return defer.promise; } /** * 當inputPromise狀態由未完成變成fulfil時,調用function(fulfilled) * 當inputPromise狀態由未完成變成rejected時,調用function(rejected) * 將then返回的promise賦給outputPromise * function(fulfilled) 和 function(rejected) 通過拋出異常將outputPromise的狀態由 * 未完成改變為reject * @private */ var outputPromise = getInputPromise().then(function(fulfilled){ throw new Error('fulfilled'); },function(rejected){ throw new Error('rejected'); }); /** * 當outputPromise狀態由未完成變成fulfil時,調用function(fulfilled)。 * 當outputPromise狀態由未完成變成rejected, 調用function(rejected)。 */ outputPromise.then(function(fulfilled){ console.log('fulfilled: ' + fulfilled); },function(rejected){ console.log('rejected: ' + rejected); }); /** * 將inputPromise的狀態由未完成變成rejected */ defer.reject(); //控制臺打印 rejected [Error:rejected] /** * 將inputPromise的狀態由未完成變成fulfilled */ //defer.resolve(); //控制臺打印 rejected [Error:fulfilled] ~~~ * 當function(fulfilled)或者function(rejected)返回一個promise時,outputPromise就會成為這個新的promise. 這樣做有什么意義呢? 主要在于聚合結果(Q.all),管理延時,異常恢復等等 比如說我們想要讀取一個文件的內容,然后把這些內容打印出來。可能會寫出這樣的代碼: ~~~ //錯誤的寫法 var outputPromise = getInputPromise().then(function(fulfilled){ fs.readFile('test.txt','utf8',function(err,data){ return data; }); }); ~~~ 然而這樣寫是錯誤的,因為function(fulfilled)并沒有返回任何值。需要下面的方式: ~~~ var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通過defer獲得promise * @private */ function getInputPromise() { return defer.promise; } /** * 當inputPromise狀態由未完成變成fulfil時,調用function(fulfilled) * 當inputPromise狀態由未完成變成rejected時,調用function(rejected) * 將then返回的promise賦給outputPromise * function(fulfilled)將新的promise賦給outputPromise * 未完成改變為reject * @private */ var outputPromise = getInputPromise().then(function(fulfilled){ var myDefer = Q.defer(); fs.readFile('test.txt','utf8',function(err,data){ if(!err && data) { myDefer.resolve(data); } }); return myDefer.promise; },function(rejected){ throw new Error('rejected'); }); /** * 當outputPromise狀態由未完成變成fulfil時,調用function(fulfilled),控制臺打印test.txt文件內容。 * */ outputPromise.then(function(fulfilled){ console.log(fulfilled); },function(rejected){ console.log(rejected); }); /** * 將inputPromise的狀態由未完成變成rejected */ //defer.reject(); /** * 將inputPromise的狀態由未完成變成fulfilled */ defer.resolve(); //控制臺打印出 test.txt 的內容 ~~~ ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#方法傳遞)方法傳遞 方法傳遞有些類似于Java中的try和catch。當一個異常沒有響應的捕獲時,這個異常會接著往下傳遞。 方法傳遞的含義是當一個狀態沒有響應的回調函數,就會沿著then往下找。 * 沒有提供function(rejected) ~~~ var outputPromise = getInputPromise().then(function(fulfilled){}) ~~~ 如果inputPromise的狀態由未完成變成rejected, 此時對rejected的處理會由outputPromise來完成。 ~~~ var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通過defer獲得promise * @private */ function getInputPromise() { return defer.promise; } /** * 當inputPromise狀態由未完成變成fulfil時,調用function(fulfilled) * 當inputPromise狀態由未完成變成rejected時,這個rejected會傳向outputPromise */ var outputPromise = getInputPromise().then(function(fulfilled){ return 'fulfilled' }); outputPromise.then(function(fulfilled){ console.log('fulfilled: ' + fulfilled); },function(rejected){ console.log('rejected: ' + rejected); }); /** * 將inputPromise的狀態由未完成變成rejected */ defer.reject('inputpromise rejected'); //控制臺打印rejected: inputpromise rejected /** * 將inputPromise的狀態由未完成變成fulfilled */ //defer.resolve(); ~~~ * 沒有提供function(fulfilled) ~~~ var outputPromise = getInputPromise().then(null,function(rejected){}) ~~~ 如果inputPromise的狀態由未完成變成fulfilled, 此時對fulfil的處理會由outputPromise來完成。 ~~~ var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通過defer獲得promise * @private */ function getInputPromise() { return defer.promise; } /** * 當inputPromise狀態由未完成變成fulfil時,傳遞給outputPromise * 當inputPromise狀態由未完成變成rejected時,調用function(rejected) * function(fulfilled)將新的promise賦給outputPromise * 未完成改變為reject * @private */ var outputPromise = getInputPromise().then(null,function(rejected){ return 'rejected'; }); outputPromise.then(function(fulfilled){ console.log('fulfilled: ' + fulfilled); },function(rejected){ console.log('rejected: ' + rejected); }); /** * 將inputPromise的狀態由未完成變成rejected */ //defer.reject('inputpromise rejected'); /** * 將inputPromise的狀態由未完成變成fulfilled */ defer.resolve('inputpromise fulfilled'); //控制臺打印fulfilled: inputpromise fulfilled ~~~ * 可以使用fail(function(error))來專門針對錯誤處理,而不是使用then(null,function(error)) ~~~ var outputPromise = getInputPromise().fail(function(error){}) ~~~ 看這個例子 ~~~ var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通過defer獲得promise * @private */ function getInputPromise() { return defer.promise; } /** * 當inputPromise狀態由未完成變成fulfil時,調用then(function(fulfilled)) * 當inputPromise狀態由未完成變成rejected時,調用fail(function(error)) * function(fulfilled)將新的promise賦給outputPromise * 未完成改變為reject * @private */ var outputPromise = getInputPromise().then(function(fulfilled){ return fulfilled; }).fail(function(error){ console.log('fail: ' + error); }); /** * 將inputPromise的狀態由未完成變成rejected */ defer.reject('inputpromise rejected');//控制臺打印fail: inputpromise rejected /** * 將inputPromise的狀態由未完成變成fulfilled */ //defer.resolve('inputpromise fulfilled'); ~~~ * 可以使用progress(function(progress))來專門針對進度信息進行處理,而不是使用?`then(function(success){},function(error){},function(progress){})` ~~~ var Q = require('q'); var defer = Q.defer(); /** * 獲取初始promise * @private */ function getInitialPromise() { return defer.promise; } /** * 為promise設置progress信息處理函數 */ var outputPromise = getInitialPromise().then(function(success){ }).progress(function(progress){ console.log(progress); }); defer.notify(1); defer.notify(2); //控制臺打印1,2 ~~~ ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#promise鏈)promise鏈 promise鏈提供了一種讓函數順序執行的方法。 函數順序執行是很重要的一個功能。比如知道用戶名,需要根據用戶名從數據庫中找到相應的用戶,然后將用戶信息傳給下一個函數進行處理。 ~~~ var Q = require('q'); var defer = Q.defer(); //一個模擬數據庫 var users = [{'name':'andrew','passwd':'password'}]; function getUsername() { return defer.promise; } function getUser(username){ var user; users.forEach(function(element){ if(element.name === username) { user = element; } }); return user; } //promise鏈 getUsername().then(function(username){ return getUser(username); }).then(function(user){ console.log(user); }); defer.resolve('andrew'); ~~~ 我們通過兩個then達到讓函數順序執行的目的。 then的數量其實是沒有限制的。當然,then的數量過多,要手動把他們鏈接起來是很麻煩的。比如 ~~~ foo(initialVal).then(bar).then(baz).then(qux) ~~~ 這時我們需要用代碼來動態制造promise鏈 ~~~ var funcs = [foo,bar,baz,qux] var result = Q(initialVal) funcs.forEach(function(func){ result = result.then(func) }) return result ~~~ 當然,我們可以再簡潔一點 ~~~ var funcs = [foo,bar,baz,qux] funcs.reduce(function(pre,current),Q(initialVal){ return pre.then(current) }) ~~~ 看一個具體的例子 ~~~ function foo(result) { console.log(result); return result+result; } //手動鏈接 Q('hello').then(foo).then(foo).then(foo); //控制臺輸出: hello // hellohello // hellohellohello //動態鏈接 var funcs = [foo,foo,foo]; var result = Q('hello'); funcs.forEach(function(func){ result = result.then(func); }); //精簡后的動態鏈接 funcs.reduce(function(prev,current){ return prev.then(current); },Q('hello')); ~~~ 對于promise鏈,最重要的是需要理解為什么這個鏈能夠順序執行。如果能夠理解這點,那么以后自己寫promise鏈可以說是輕車熟路啊。 ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#promise組合)promise組合 回到我們一開始讀取文件內容的例子。如果現在讓我們把它改寫成promise鏈,是不是很簡單呢? ~~~ var Q = require('q'), fs = require('fs'); function printFileContent(fileName) { return function(){ var defer = Q.defer(); fs.readFile(fileName,'utf8',function(err,data){ if(!err && data) { console.log(data); defer.resolve(); } }) return defer.promise; } } //手動鏈接 printFileContent('sample01.txt')() .then(printFileContent('sample02.txt')) .then(printFileContent('sample03.txt')) .then(printFileContent('sample04.txt')); //控制臺順序打印sample01到sample04的內容 ~~~ 很有成就感是不是。然而如果仔細分析,我們會發現為什么要他們順序執行呢,如果他們能夠并行執行不是更好嗎? 我們只需要在他們都執行完成之后,得到他們的執行結果就可以了。 我們可以通過Q.all([promise1,promise2...])將多個promise組合成一個promise返回。 注意: 1. 當all里面所有的promise都fulfil時,Q.all返回的promise狀態變成fulfil 2. 當任意一個promise被reject時,Q.all返回的promise狀態立即變成reject 我們來把上面讀取文件內容的例子改成并行執行吧 ~~~ var Q = require('q'); var fs = require('fs'); /** *讀取文件內容 *@private */ function printFileContent(fileName) { //Todo: 這段代碼不夠簡潔。可以使用Q.denodeify來簡化 var defer = Q.defer(); fs.readFile(fileName,'utf8',function(err,data){ if(!err && data) { console.log(data); defer.resolve(fileName + ' success '); }else { defer.reject(fileName + ' fail '); } }) return defer.promise; } Q.all([printFileContent('sample01.txt'),printFileContent('sample02.txt'),printFileContent('sample03.txt'),printFileContent('sample04.txt')]) .then(function(success){ console.log(success); }); //控制臺打印各個文件內容 順序不一定 ~~~ 現在知道Q.all會在任意一個promise進入reject狀態后立即進入reject狀態。如果我們需要等到所有的promise都發生狀態后(有的fulfil, 有的reject),再轉換Q.all的狀態, 這時我們可以使用Q.allSettled ~~~ var Q = require('q'), fs = require('fs'); /** *讀取文件內容 *@private */ function printFileContent(fileName) { //Todo: 這段代碼不夠簡潔。可以使用Q.denodeify來簡化 var defer = Q.defer(); fs.readFile(fileName,'utf8',function(err,data){ if(!err && data) { console.log(data); defer.resolve(fileName + ' success '); }else { defer.reject(fileName + ' fail '); } }) return defer.promise; } Q.allSettled([printFileContent('nosuchfile.txt'),printFileContent('sample02.txt'),printFileContent('sample03.txt'),printFileContent('sample04.txt')]) .then(function(results){ results.forEach( function(result) { console.log(result.state); } ); }); ~~~ ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#結束promise鏈)結束promise鏈 通常,對于一個promise鏈,有兩種結束的方式。第一種方式是返回最后一個promise 如?`return foo().then(bar);` 第二種方式就是通過done來結束promise鏈 如?`foo().then(bar).done()` 為什么需要通過done來結束一個promise鏈呢? 如果在我們的鏈中有錯誤沒有被處理,那么在一個正確結束的promise鏈中,這個沒被處理的錯誤會通過異常拋出。 ~~~ var Q = require('q'); /** *@private */ function getPromise(msg,timeout,opt) { var defer = Q.defer(); setTimeout(function(){ console.log(msg); if(opt) defer.reject(msg); else defer.resolve(msg); },timeout); return defer.promise; } /** *沒有用done()結束的promise鏈 *由于getPromse('2',2000,'opt')返回rejected, getPromise('3',1000)就沒有執行 *然后這個異常并沒有任何提醒,是一個潛在的bug */ getPromise('1',3000) .then(function(){return getPromise('2',2000,'opt')}) .then(function(){return getPromise('3',1000)}); /** *用done()結束的promise鏈 *有異常拋出 */ getPromise('1',3000) .then(function(){return getPromise('2',2000,'opt')}) .then(function(){return getPromise('3',1000)}) .done(); ~~~ ## [](https://github.com/alsotang/node-lessons/tree/master/lesson17#結束語)結束語 當你理解完上面所有的知識點時,你就會正確高效的使用promise了。本節只是講了promise的原理和幾個基本的API,不過你掌握了這些之后,再去看q的文檔,應該很容易就能理解各個api的意圖。
                  <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>

                              哎呀哎呀视频在线观看