日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

5、this调用语句必须是构造函数中的第一个可执行语句_ES6中的Promise和Generator详解...

發布時間:2024/7/23 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 5、this调用语句必须是构造函数中的第一个可执行语句_ES6中的Promise和Generator详解... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介

ES6中除了上篇文章講過的語法新特性和一些新的API之外,還有兩個非常重要的新特性就是Promise和Generator,今天我們將會詳細講解一下這兩個新特性。

Promise

什么是Promise

Promise 是異步編程的一種解決方案,比傳統的解決方案“回調函數和事件”更合理和更強大。

所謂Promise,簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。

從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。

Promise的特點

Promise有兩個特點:

  • 對象的狀態不受外界影響。
  • Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和Rejected(已失敗)。

    只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。

  • 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。
  • Promise對象的狀態改變,只有兩種可能:從Pending變為Resolved和從Pending變為Rejected。

    這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

    Promise的優點

    Promise將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。

    Promise對象提供統一的接口,使得控制異步操作更加容易。

    Promise的缺點

  • 無法取消Promise,一旦新建它就會立即執行,無法中途取消。
  • 如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。
  • 當處于Pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
  • Promise的用法

    Promise對象是一個構造函數,用來生成Promise實例:

    var promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操作成功 */){ resolve(value); } else { reject(error); } } );

    promise可以接then操作,then操作可以接兩個function參數,第一個function的參數就是構建Promise的時候resolve的value,第二個function的參數就是構建Promise的reject的error。

    promise.then(function(value) { // success }, function(error) { // failure } );

    我們看一個具體的例子:

    function timeout(ms){return new Promise(((resolve, reject) => {setTimeout(resolve,ms,'done');})) }timeout(100).then(value => console.log(value));

    Promise中調用了一個setTimeout方法,并會定時觸發resolve方法,并傳入參數done。

    最后程序輸出done。

    Promise的執行順序

    Promise一經創建就會立馬執行。但是Promise.then中的方法,則會等到一個調用周期過后再次調用,我們看下面的例子:

    let promise = new Promise(((resolve, reject) => {console.log('Step1');resolve(); }));promise.then(() => {console.log('Step3'); });console.log('Step2');輸出: Step1 Step2 Step3

    Promise.prototype.then()

    then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。因此可以采用鏈式寫法,即then方法后面再調用另一個then方法.

    getJSON("/users.json").then(function(json){return json.name; }).then(function(name){console.log(name); });

    上面的代碼使用then方法,依次指定了兩個回調函數。第一個回調函數完成以后,會將返回結果作為參數,傳入第二個回調函數

    Promise.prototype.catch()

    Promise.prototype.catch方法是.then(null, rejection)的別名,用于指定發生錯誤時的回調函數。

    getJSON("/users.json").then(function(json){return json.name; }).catch(function(error){console.log(error); });

    Promise 對象的錯誤具有“冒泡”性質,會一直向后傳遞,直到被捕獲為止。也就是說,錯誤總是會被下一個catch語句捕獲

    getJSON("/users.json").then(function(json){return json.name; }).then(function(name){console.log(name); }).catch(function(error){//處理前面所有產生的錯誤console.log(error); });

    Promise.all()

    Promise.all方法用于將多個Promise實例,包裝成一個新的Promise實例

    var p = Promise.all([p1,p2,p3]);
  • 只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。
  • 只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。
  • Promise.race()

    Promise.race方法同樣是將多個Promise實例,包裝成一個新的Promise實例

    var p = Promise.race([p1,p2,p3]);

    只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數.

    Promise.resolve()

    Promise.resolve()將現有對象轉為Promise對象.

    Promise.resolve('js'); //等價于 new Promise(resolve => resolve('js'));

    那么什么樣的對象能夠轉化成為Promise對象呢?

  • 參數是一個Promise實例
  • 參數是一個thenable對象
  • 參數不是具有then方法的對象,或根本就不是對象
  • 不帶有任何參數
  • Promise.reject()

    Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態為rejected

    var p = Promise.reject('error'); //等價于 var p = new Promise((resolve,reject) => reject('error'));

    Promise.reject()方法的參數,會原封不動地作為reject的理由,變成后續方法的參數。這一點與Promise.resolve方法不一致

    done()

    Promise對象的回調鏈,不管以then方法或catch方法結尾,要是最后一個方法拋出錯誤,都有可能無法捕捉到(因為Promise內部的錯誤不會冒泡到全局)。因此,我們可以提供一個done方法,總是處于回調鏈的尾端,保證拋出任何可能出現的錯誤

    asyncFunc().then(f1).catch(f2).then(f3).done();

    finally()

    finally方法用于指定不管Promise對象最后狀態如何,都會執行的操作。它與done方法的最大區別,它接受一個普通的回調函數作為參數,該函數不管怎樣都必須執行.

    server.listen(1000).then(function(){//do something }.finally(server.stop);

    Generator

    什么是Generator

    Generator 函數是 ES6 提供的一種異步編程解決方案

    從語法上,首先可以把它理解成,Generator函數是一個狀態機,封裝了多個內部狀態

    執行 Generator 函數會返回一個遍歷器對象.

    形式上,Generator 函數是一個普通函數,但是有兩個特征。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield語句,定義不同的內部狀態。

    舉個例子:

    function * helloWorldGenerator(){yield 'hello';yield 'world';return 'ending'; }var gen = helloWorldGenerator();

    輸出結果:

    console.log(gen.next()); console.log(gen.next()); console.log(gen.next());{ value: 'hello', done: false } { value: 'world', done: false } { value: 'ending', done: true }

    yield

    遍歷器對象的next方法的運行邏輯如下:

    (1)遇到yield語句,就暫停執行后面的操作,并將緊跟在yield后面的那個表達式的值,作為返回的對象的value屬性值。

    (2)下一次調用next方法時,再繼續往下執行,直到遇到下一個yield語句。

    (3)如果沒有再遇到新的yield語句,就一直運行到函數結束,直到return語句為止,并將return語句后面的表達式的值,作為返回的對象的value屬性值。

    (4)如果該函數沒有return語句,則返回的對象的value屬性值為undefined。

    注意,yield句本身沒有返回值,或者說總是返回undefined。

    next方法可以帶一個參數,該參數就會被當作上一個yield語句的返回值。

    function * f() {for( let i =0; true; i++){let reset = yield i;if(reset){i = -1;}} }let g = f(); console.log(g.next()); console.log(g.next()); console.log(g.next(true));

    輸出結果:

    { value: 0, done: false } { value: 1, done: false } { value: 0, done: false }

    可以看到最后的一步,我們使用next傳入的true替代了i的值,最后導致i= -1 + 1 = 0.

    我們再看一個例子:

    function * f2(x){var y = 2 * ( yield ( x + 1));var z = yield (y / 3);return (x + y + z); }var r1= f2(5); console.log(r1.next()); console.log(r1.next()); console.log(r1.next());var r2= f2(5); console.log(r2.next()); console.log(r2.next(12)); console.log(r2.next(13));

    輸出結果:

    { value: 6, done: false } { value: NaN, done: false } { value: NaN, done: true }{ value: 6, done: false } { value: 8, done: false } { value: 42, done: true }

    如果next不傳值的話,yield本身是沒有返回值的,所以我們會得到NaN。

    但是如果next傳入特定的值,則該值會替換該yield,成為真正的返回值。

    yield *

    如果在 Generator 函數內部,調用另一個 Generator 函數,默認情況下是沒有效果的

    function * a1(){yield 'a';yield 'b'; }function * b1(){yield 'x';a1();yield 'y'; }for(let v of b1()){console.log(v); }

    輸出結果:

    x y

    可以看到,在b1中調用a1是沒有效果的。

    將上面的例子修改一下:

    function * a1(){yield 'a';yield 'b'; }function * b1(){yield 'x';yield * a1();yield 'y'; }for(let v of b1()){console.log(v); }

    輸出結果:

    x a b y

    異步操作的同步化表達

    Generator函數的暫停執行的效果,意味著可以把異步操作寫在yield語句里面,等到調用next方法時再往后執行。這實際上等同于不需要寫回調函數了,因為異步操作的后續操作可以放在yield語句下面,反正要等到調用next方法時再執行。所以,Generator函數的一個重要實際意義就是用來處理異步操作,改寫回調函數。

    我們看一個怎么通過Generator來獲取一個Ajax的結果。

    function * ajaxCall(){let result = yield request("http://www.flydean.com");let resp = JSON.parse(result);console.log(resp.value); }function request(url){makeAjaxCall(url, function(response){it.next(response);}); }var it = ajaxCall(); it.next();

    我們使用一個yield來獲取異步執行的結果。但是我們如何將這個yield傳給result變量呢?要記住yield本身是沒有返回值的。

    我們需要調用generator的next方法,將異步執行的結果傳進去。這就是我們在request方法中做的事情。

    Generator 的異步應用

    什么是異步應用呢?

    所謂”異步”,簡單說就是一個任務不是連續完成的,可以理解成該任務被人為分成兩段,先執行第一段,然后轉而執行其他任務,等做好了準備,再回過頭執行第二段。

    比如,有一個任務是讀取文件進行處理,任務的第一段是向操作系統發出請求,要求讀取文件。然后,程序執行其他任務,等到操作系統返回文件,再接著執行任務的第二段(處理文件)。這種不連續的執行,就叫做異步。

    相應地,連續的執行就叫做同步。由于是連續執行,不能插入其他任務,所以操作系統從硬盤讀取文件的這段時間,程序只能干等著。

    ES6誕生以前,異步編程的方法,大概有下面四種。
    回調函數
    事件監聽
    發布/訂閱
    Promise 對象

    回調函數

    fs.readFile(fileA, 'utf-8', function(error,data){fs.readFile(fileB, 'utf-8', function(error,data){ } })

    如果依次讀取兩個以上的文件,就會出現多重嵌套。代碼不是縱向發展,而是橫向發展,很快就會亂成一團,無法管理。因為多個異步操作形成了強耦合,只要有一個操作需要修改,它的上層回調函數和下層回調函數,可能都要跟著修改。這種情況就稱為”回調函數地獄”(callback hell)。

    Promise

    Promise 對象就是為了解決這個問題而提出的。它不是新的語法功能,而是一種新的寫法,允許將回調函數的嵌套,改成鏈式調用。

    let readFile = require('fs-readfile-promise'); readFile(fileA).then(function(){return readFile(fileB); }).then(function(data){console.log(data); })

    Thunk函數和異步函數自動執行

    在講Thunk函數之前,我們講一下函數的調用有兩種方式,一種是傳值調用,一種是傳名調用。

    “傳值調用”(call by value),即在進入函數體之前,就計算x + 5的值(等于6),再將這個值傳入函數f。C語言就采用這種策略。

    “傳名調用”(call by name),即直接將表達式x + 5傳入函數體,只在用到它的時候求值。

    編譯器的“傳名調用”實現,往往是將參數放到一個臨時函數之中,再將這個臨時函數傳入函數體。這個臨時函數就叫做 Thunk 函數。

    舉個例子:

    function f(m){return m * 2; }f(x + 5);

    上面的代碼等于:

    var thunk = function () {return x + 5; } function f(thunk){return thunk() * 2; }

    在 JavaScript 語言中,Thunk函數替換的不是表達式,而是多參數函數,將其替換成一個只接受回調函數作為參數的單參數函數。

    怎么解釋呢?

    比如nodejs中的:

    fs.readFile(filename,[encoding],[callback(err,data)])

    readFile接收3個參數,其中encoding是可選的。我們就以兩個參數為例。

    一般來說,我們這樣調用:

    fs.readFile(fileA,callback);

    那么有沒有辦法將其改寫成為單個參數的function的級聯調用呢?

    var Thunk = function (fn){return function (...args){return functon (callback){return fn.call(this,...args, callback);}} }var readFileThunk = Thunk(fs.readFile); readFileThunk(fileA)(callback);

    可以看到上面的Thunk將兩個參數的函數改寫成為了單個參數函數的級聯方式。或者說Thunk是接收一個callback并執行方法的函數。

    這樣改寫有什么用呢?Thunk函數現在可以用于 Generator 函數的自動流程管理。

    之前在講Generator的時候,如果Generator中有多個yield的異步方法,那么我們需要在next方法中傳入這些異步方法的執行結果。

    手動傳入異步執行結果當然是可以的。但是有沒有自動執行的辦法呢?

    let fs = require('fs'); let thunkify = require('thunkify'); let readFileThunk = thunkify(fs.readFile);let gen = function * (){let r1 = yield readFileThunk('/tmp/file1');console.log(r1.toString());let r2 = yield readFileThunk('/tmp/file2');console.log(r2.toString()); }let g = gen();function run(fn){let gen = fn();function next (err, data){let result = gen.next(data);if(result.done) return;result.value(next);}next(); }run(g);

    gen.next返回的是一個對象,對象的value就是Thunk函數,我們向Thunk函數再次傳入next callback,從而出發下一次的yield操作。

    有了這個執行器,執行Generator函數方便多了。不管內部有多少個異步操作,直接把 Generator 函數傳入run函數即可。當然,前提是每一個異步操作,都要是Thunk函數,也就是說,跟在yield命令后面的必須是Thunk函數。

    總結

    Promise和Generator是ES6中引入的非常中要的語法,后面的koa框架就是Generator的一種具體的實現。我們會在后面的文章中詳細講解koa的使用,敬請期待。

    本文作者:flydean程序那些事本文鏈接:http://www.flydean.com/es6-promise-generator/本文來源:flydean的博客歡迎關注我的公眾號:「程序那些事」最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!

    總結

    以上是生活随笔為你收集整理的5、this调用语句必须是构造函数中的第一个可执行语句_ES6中的Promise和Generator详解...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 精品国产一区二区三区久久久久久 | ktv做爰视频一区二区 | 亚洲第一看片 | 亚洲一区二区三区在线免费观看 | 国产男女猛烈无遮挡免费视频动漫 | 法国极品成人h版 | 夫妻露脸自拍[30p] | 日韩成人专区 | 天天摸天天碰 | 在线观看免费av网站 | 夜夜爽网站 | 欧美偷拍另类 | 91香蕉国产在线观看软件 | 91干干干 | 欧美日韩精品一区二区三区视频播放 | 欧美精品入口蜜桃 | 中文字幕久久熟女蜜桃 | 曰本三级日本三级日本三级 | 抱着老师的嫩臀猛然挺进视频 | 黄色欧美大片 | 国产一区二区电影 | 2021av视频 | 9i在线看片成人免费 | 波多野结衣一区二区三区四区 | 亚洲熟妇无码乱子av电影 | r级无码视频在线观看 | 国产精品久久777777 | 久久99久久99精品免观看软件 | 福利姬在线观看 | 成人性生交大全免 | 免费看黄网站在线 | 久久九九色 | 大肉大捧一进一出好爽视频 | 精品777| 亚洲操操操 | 黄色一级黄色片 | 伊人天堂av| 日韩成人精品在线 | 娇妻玩4p被三个男人伺候电影 | 丁香综合激情 | 狠狠干狠狠操 | 超碰69| 巨胸大乳www视频免费观看 | 九九精品视频在线观看 | 老色鬼在线 | 竹菊影视一区二区三区 | 18禁免费观看网站 | 天天天干干干 | 欧美成人精品一区二区综合免费 | 欧美午夜精品一区二区蜜桃 | 亚州av一区二区 | juliaann欧美二区三区 | 天天操网站 | 人人草超碰 | 日韩a级片 | 午夜精品一区二区三 | 伊人99在线 | jizzjizz国产 | 第一福利在线 | www九九九 | av官网| 精品视频久久久久久 | 日韩av在线免费 | 精品一久久 | 日韩一区二区视频在线观看 | 国内爆初菊对白视频 | 摸丰满大乳奶水www免费 | 成人毛片在线免费观看 | 日日操影院 | 国产 欧美 自拍 | 3d动漫啪啪精品一区二区中文字幕 | 99在线精品视频免费观看软件 | 91国自啪 | 日本高潮网站 | 青青久在线视频 | mm1313亚洲精品 | 懂色av蜜臀av粉嫩av分享吧最新章节 | 国产精品久久久久久免费免熟 | 人妻丰满熟妇av无码区免 | 91福利视频在线观看 | 简单av在线| 精品人妻无码一区二区三区换脸 | 一级成人免费视频 | caoporn视频在线| a级片在线播放 | 超碰免费在线播放 | 91黄免费| 人妻系列一区 | 麻豆伊甸园 | 久久久九九九热 | 欧美精品一区二区三 | 国内精品视频在线 | 国产视频福利在线观看 | 涩久久 | 欧美做受xxxxxⅹ性视频 | 午夜av免费观看 | 精品国产三级片在线观看 | 一级黄色性片 | 天天操穴 |