中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

使用Promise解決多層異步調用的簡單學習心得
來源:易賢網 閱讀:1416 次 日期:2016-06-27 16:01:55
溫馨提示:易賢網小編為您整理了“使用Promise解決多層異步調用的簡單學習心得”,方便廣大網友查閱!

下面小編就為大家帶來一篇使用Promise解決多層異步調用的簡單學習心得。小編覺得挺不錯的,現在分享給大家,也給大家做個參考。

前言

第一次接觸到Promise這個東西,是2012年微軟發布Windows8操作系統后抱著作死好奇的心態研究用html5寫Metro應用的時候。當時配合html5提供的WinJS庫里面的異步接口全都是Promise形式,這對那時候剛剛畢業一點javascript基礎都沒有的我而言簡直就是天書。我當時想的是,微軟又在腦洞大開的瞎搗鼓了。

結果沒想到,到了2015年,Promise居然寫進ES6標準里面了。而且一項調查顯示,js程序員們用這玩意用的還挺high。

諷刺的是,作為早在2012年就在Metro應用開發接口里面廣泛使用Promise的微軟,其自家瀏覽器IE直到2015年壽終正寢了都還不支持Promise,看來微軟不是沒有這個技術,而是真的對IE放棄治療了。。。

現在回想起來,當時看到Promise最頭疼的,就是初學者看起來匪夷所思,也是最被js程序員廣為稱道的特性:then函數調用鏈。

then函數調用鏈,從其本質上而言,就是對多個異步過程的依次調用,本文就從這一點著手,對Promise這一特性進行研究和學習。

Promise解決的問題

考慮如下場景,函數延時2秒之后打印一行日志,再延時3秒打印一行日志,再延時4秒打印一行日志,這在其他的編程語言當中是非常簡單的事情,但是到了js里面就比較費勁,代碼大約會寫成下面的樣子:

var myfunc = function() {  

  setTimeout(function() {

    console.log("log1");

    setTimeout(function() {

      console.log("log2");

      setTimeout(function() {

        console.log("log3");

      }, 4000);

    }, 3000); 

  }, 2000);

}

由于嵌套了多層回調結構,這里形成了一個典型的金字塔結構。如果業務邏輯再復雜一些,就會變成令人聞風喪膽的回調地獄。

如果意識比較好,知道提煉出簡單的函數,那么代碼差不多是這個樣子:

var func1 = function() {

  setTimeout(func2, 2000);

};

var func2 = function() {

  console.log("log1");

  setTimeout(func3, 3000);

};

var func3 = function() {

  console.log("log2");

  setTimeout(func4, 4000);

};

var func4 = function() {

  console.log("log3");

};

這樣看起來稍微好一點了,但是總覺得有點怪怪的。。。好吧,其實我js水平有限,說不上來為什么這樣寫不好。如果你知道為什么這樣寫不太好所以發明了Promise,請告訴我。

現在讓我們言歸正傳,說說Promise這個東西。

Promise的描述

這里請允許我引用MDN對Promise的描述:

Promise 對象用于延遲(deferred) 計算和異步(asynchronous ) 計算.。一個Promise對象代表著一個還未完成,但預期將來會完成的操作。

Promise 對象是一個返回值的代理,這個返回值在promise對象創建時未必已知。它允許你為異步操作的成功或失敗指定處理方法。 這使得異步方法可以像同步方法那樣返回值:異步方法會返回一個包含了原返回值的 promise 對象來替代原返回值。

Promise對象有以下幾種狀態:

•pending: 初始狀態, 非 fulfilled 或 rejected。

•fulfilled: 成功的操作。

•rejected: 失敗的操作。

pending狀態的promise對象既可轉換為帶著一個成功值的fulfilled 狀態,也可變為帶著一個失敗信息的 rejected 狀態。當狀態發生轉換時,promise.then綁定的方法(函數句柄)就會被調用。(當綁定方法時,如果 promise對象已經處于 fulfilled 或 rejected 狀態,那么相應的方法將會被立刻調用, 所以在異步操作的完成情況和它的綁定方法之間不存在競爭條件。)

更多關于Promise的描述和示例可以參考MDN的Promise條目,或者MSDN的Promise條目。

嘗試使用Promise解決我們的問題

基于以上對Promise的了解,我們知道可以使用它來解決多層回調嵌套后的代碼蠢笨難以維護的問題。關于Promise的語法和參數上面給出的兩個鏈接已經說的很清楚了,這里不重復,直接上代碼。

我們先來嘗試一個比較簡單的情況,只執行一次延時和回調:

new Promise(function(res, rej) {

  console.log(Date.now() + " start setTimeout");

  setTimeout(res, 2000);

}).then(function() {

  console.log(Date.now() + " timeout call back");

});

看起來和MSDN里的示例也沒什么區別,執行結果如下:

$ node promisTest.js

1450194136374 start setTimeout

1450194138391 timeout call back

那么如果我們要再做一個延時呢,那么我可以這樣寫:

new Promise(function(res, rej) {

  console.log(Date.now() + " start setTimeout 1");

  setTimeout(res, 2000);

}).then(function() {

  console.log(Date.now() + " timeout 1 call back");

  new Promise(function(res, rej) {

    console.log(Date.now() + " start setTimeout 2");

    setTimeout(res, 3000);

  }).then(function() {

    console.log(Date.now() + " timeout 2 call back");

  })

});

似乎也能正確運行:

$ node promisTest.js

1450194338710 start setTimeout 1

1450194340720 timeout 1 call back

1450194340720 start setTimeout 2

1450194343722 timeout 2 call back

不過代碼看起來蠢萌蠢萌的是不是,而且隱約又在搭金字塔了。這和引入Promise的目的背道而馳。

那么問題出在哪呢?正確的姿勢又是怎樣的?

答案藏在then函數以及then函數的onFulfilled(或者叫onCompleted)回調函數的返回值里面。

首先明確的一點是,then函數會返回一個新的Promise變量,你可以再次調用這個新的Promise變量的then函數,像這樣:

new Promise(...).then(...)

  .then(...).then(...).then(...)...

而then函數返回的是什么樣的Promies,取決于onFulfilled回調的返回值。

事實上,onFulfilled可以返回一個普通的變量,也可以是另一個Promise變量。

如果onFulfilled返回的是一個普通的值,那么then函數會返回一個默認的Promise變量。執行這個Promise的then函數會使Promise立即被滿足,執行onFulfilled函數,而這個onFulfilled的入參,即是上一個onFulfilled的返回值。

而如果onFulfilled返回的是一個Promise變量,那個這個Promise變量就會作為then函數的返回值。

關于then函數和onFulfilled函數的返回值的這一系列設定,MDN和MSDN上的文檔都沒有明確的正面描述,至于ES6官方文檔ECMAScript 2015 (6th Edition, ECMA-262)。。。我的水平有限實在看不懂,如果哪位高手能解釋清楚官方文檔里面對著兩個返回值的描述,請一定留言指教!!!

所以以上為我的自由發揮,語言組織的有點拗口,上代碼看一下大家就明白了。

首先是返回普通變量的情況:

new Promise(function(res, rej) {

  console.log(Date.now() + " start setTimeout 1");

  setTimeout(res, 2000);

}).then(function() {

  console.log(Date.now() + " timeout 1 call back");

  return 1024;

}).then(function(arg) {

  console.log(Date.now() + " last onFulfilled return " + arg);  

});

以上代碼執行結果為:

$ node promisTest.js

1450277122125 start setTimeout 1

1450277124129 timeout 1 call back

1450277124129 last onFulfilled return 1024

有點意思對不對,但這不是關鍵。關鍵是onFulfilled函數返回一個Promise變量可以使我們很方便的連續調用多個異步過程。比如我們可以這樣來嘗試連續做兩個延時操作:

new Promise(function(res, rej) {

  console.log(Date.now() + " start setTimeout 1");

  setTimeout(res, 2000);

}).then(function() {

  console.log(Date.now() + " timeout 1 call back");

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start setTimeout 2");

    setTimeout(res, 3000);

  });

}).then(function() {

  console.log(Date.now() + " timeout 2 call back");

});

執行結果如下:

$ node promisTest.js

1450277510275 start setTimeout 1

1450277512276 timeout 1 call back

1450277512276 start setTimeout 2

1450277515327 timeout 2 call back

如果覺得這也沒什么了不起,那再多來幾次也不在話下:

new Promise(function(res, rej) {

  console.log(Date.now() + " start setTimeout 1");

  setTimeout(res, 2000);

}).then(function() {

  console.log(Date.now() + " timeout 1 call back");

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start setTimeout 2");

    setTimeout(res, 3000);

  });

}).then(function() {

  console.log(Date.now() + " timeout 2 call back");

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start setTimeout 3");

    setTimeout(res, 4000);

  });

}).then(function() {

  console.log(Date.now() + " timeout 3 call back");

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start setTimeout 4");

    setTimeout(res, 5000);

  });

}).then(function() {

  console.log(Date.now() + " timeout 4 call back");

});

$ node promisTest.js

1450277902714 start setTimeout 1

1450277904722 timeout 1 call back

1450277904724 start setTimeout 2

1450277907725 timeout 2 call back

1450277907725 start setTimeout 3

1450277911730 timeout 3 call back

1450277911730 start setTimeout 4

1450277916744 timeout 4 call back

可以看到,多個延時的回調函數被有序的排列下來,并沒有出現喜聞樂見的金字塔狀結構。雖然代碼里面調用的都是異步過程,但是看起來就像是全部由同步過程構成的一樣。這就是Promise帶給我們的好處。

如果你有把啰嗦的代碼提煉成單獨函數的好習慣,那就更加畫美不看了:

function timeout1() {

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start timeout1");

    setTimeout(res, 2000);

  });

}

function timeout2() {

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start timeout2");

    setTimeout(res, 3000);

  });

}

function timeout3() {

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start timeout3");

    setTimeout(res, 4000);

  });

}

function timeout4() {

  return new Promise(function(res, rej) {

    console.log(Date.now() + " start timeout4");

    setTimeout(res, 5000);

  });

}

timeout1()

  .then(timeout2)

  .then(timeout3)

  .then(timeout4)

  .then(function() {

    console.log(Date.now() + " timout4 callback");

  });

$ node promisTest.js

1450278983342 start timeout1

1450278985343 start timeout2

1450278988351 start timeout3

1450278992356 start timeout4

1450278997370 timout4 callback

接下來我們可以再繼續研究一下onFulfilled函數傳入入參的問題。

我們已經知道,如果上一個onFulfilled函數返回了一個普通的值,那么這個值為作為這個onFulfilled函數的入參;那么如果上一個onFulfilled返回了一個Promise變量,這個onFulfilled的入參又來自哪里?

答案是,這個onFulfilled函數的入參,是上一個Promise中調用resolve函數時傳入的值。

跳躍的有點大一時間無法接受對不對,讓我們來好好縷一縷。

首先,Promise.resolve這個函數是什么,用MDN上面文鄒鄒的說法

用成功值value解決一個Promise對象。如果該value為可繼續的(thenable,即帶有then方法),返回的Promise對象會“跟隨”這個value

簡而言之,這就是異步調用成功情況下的回調。

我們來看看普通的異步接口中,成功情況的回調是什么樣的,就拿nodejs的上的fs.readFile(file[, options], callback)來說,它的典型調用例子如下

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

 if (err) throw err;

 console.log(data);

});

因為對于fs.readFile這個函數而言,無論成功還是失敗,它都會調用callback這個回調函數,所以這個回調接受兩個入參,即失敗時的異常描述err和成功時的返回結果data。

那么假如我們用Promise來重構這個讀取文件的例子,我們應該怎么寫呢?

首先是封裝fs.readFile函數:

function readFile(fileName) {

  return new Promise(function(resolve, reject) {

    fs.readFile(fileName, function (err, data) {

      if (err) {

        reject(err);

      } else {

        resolve(data);

      }

    });

  });

}

其次是調用:

readFile('theFile.txt').then(

  function(data) {

    console.log(data);

  }, 

  function(err) {

    throw err;

  }  

);

想象一下,在其他語言的讀取文件的同步調用接口的里面,文件的內容通常是放在哪里?函數返回值對不對!答案出來了,這個resolve的入參是什么?就是異步調用成功情況下的返回值。

有了這個概念之后,我們就不難理解“onFulfilled函數的入參,是上一個Promise中調用resolve函數時傳入的值”這件事了。因為onFulfilled的任務,就是對上一個異步調用成功后的結果做處理的。

哎終于理順了。。。

總結

下面請允許我用一段代碼對本文講解到的要點進行總結:

function callp1() {

  console.log(Date.now() + " start callp1");

  return new Promise(function(res, rej) {

    setTimeout(res, 2000);

  });

}

function callp2() {

  console.log(Date.now() + " start callp2");

  return new Promise(function(res, rej) {

    setTimeout(function() {

      res({arg1: 4, arg2: "arg2 value"});

    }, 3000);

  });

}

function callp3(arg) {

  console.log(Date.now() + " start callp3 with arg = " + arg);

  return new Promise(function(res, rej) {

    setTimeout(function() {

      res("callp3");

    }, arg * 1000);

  });

}

callp1().then(function() {

  console.log(Date.now() + " callp1 return");

  return callp2();

}).then(function(ret) {

  console.log(Date.now() + " callp2 return with ret value = " + JSON.stringify(ret));

  return callp3(ret.arg1);

}).then(function(ret) {

  console.log(Date.now() + " callp3 return with ret value = " + ret);

})

$ node promisTest.js

1450191479575 start callp1

1450191481597 callp1 return

1450191481599 start callp2

1450191484605 callp2 return with ret value = {"arg1":4,"arg2":"arg2 value"}

1450191484605 start callp3 with arg = 4

1450191488610 callp3 return with ret value = callp3

以上這篇使用Promise解決多層異步調用的簡單學習心得就是小編分享給大家的全部內容了,希望能給大家一個參考

更多信息請查看網絡編程
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!

2026上岸·考公考編培訓報班

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
云南網警備案專用圖標
聯系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網
云南網警報警專用圖標
中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久
国产一区二区三区黄视频| 久久xxxx精品视频| 在线国产精品播放| 久久一区二区视频| 在线看不卡av| 欧美日韩国产首页在线观看| 亚洲日韩第九十九页| 欧美.日韩.国产.一区.二区| 亚洲电影有码| 欧美色精品在线视频| 亚洲视频在线二区| 国产在线视频不卡二| 久久久久久久久久久久久女国产乱| 国产真实乱偷精品视频免| 美女视频黄 久久| 亚洲免费av电影| 国产精品久久国产愉拍| 欧美一区二区三区另类| 国产专区欧美精品| 欧美精品成人| 久久久人人人| 欧美亚洲一区二区在线| 亚洲欧洲日韩在线| 国产日韩欧美在线观看| 欧美午夜在线观看| 欧美日韩国产在线播放| 欧美一区二区三区四区在线观看| 亚洲欧美国产高清| 久久av一区二区| 激情综合五月天| 欧美成人中文| 蜜臀av一级做a爰片久久| 欧美有码在线视频| 欧美一区二区精品在线| 香蕉免费一区二区三区在线观看 | 免费久久精品视频| 久久人人爽爽爽人久久久| 久久aⅴ国产紧身牛仔裤| 久久成人资源| 久久久久综合| 欧美成人亚洲成人日韩成人| 久久午夜电影| 欧美日韩国产不卡| 国产精品区一区二区三| 国产欧美日韩精品一区| 在线日韩av| 亚洲免费高清视频| 亚洲在线免费| 欧美a级在线| 一区二区三区在线免费观看| 国产视频一区欧美| 在线看片成人| 欧美特黄视频| 国产精品亚洲产品| 国产精品色午夜在线观看| 久久五月婷婷丁香社区| 国产伦精品一区| 一区二区亚洲精品| 亚洲福利视频二区| 在线亚洲免费视频| 欧美~级网站不卡| 美女视频黄a大片欧美| 日韩视频国产视频| 久久久久久久国产| 欧美日本一区| 亚洲日韩中文字幕在线播放| 香港久久久电影| 欧美人与性动交cc0o| 激情六月婷婷综合| 亚洲精品久久视频| 每日更新成人在线视频| 国产精品福利在线| 亚洲一二三四久久| 欧美性理论片在线观看片免费| 亚洲精品激情| 欧美日韩人人澡狠狠躁视频| 日韩视频精品在线观看| 免播放器亚洲| 最新高清无码专区| 玖玖玖国产精品| 国产一区二区日韩精品| 亚洲欧美日韩中文在线制服| 欧美精品一区二区三区四区| 国产欧美精品在线| 午夜精品一区二区三区电影天堂| 巨乳诱惑日韩免费av| 国产在线精品一区二区中文 | 亚洲一二三四区| 国产精品草莓在线免费观看| 99视频一区| 欧美精品乱码久久久久久按摩| 国产乱码精品一区二区三区av| 最新日韩欧美| 国产精品久久久久高潮| 午夜一区二区三区不卡视频| 国产模特精品视频久久久久| 久久精品国产99| 伊人春色精品| 欧美午夜宅男影院在线观看| 久久久久九九九九| 一区二区久久久久久| 国产日韩免费| 欧美激情综合色| 午夜精品成人在线| 亚洲第一在线综合网站| 国内精品亚洲| 伊人激情综合| 亚洲国产日韩在线一区模特| 国模私拍一区二区三区| 欧美大片在线观看一区| 免费影视亚洲| 欧美精品18videos性欧美| 久久精品91久久久久久再现| 欧美一区二区视频在线观看2020 | 日韩亚洲欧美高清| 亚洲第一在线| 亚洲乱码日产精品bd| 艳妇臀荡乳欲伦亚洲一区| 99国产欧美久久久精品| 亚洲一区免费观看| 欧美一区亚洲一区| 久久精品二区三区| 亚洲国产天堂久久国产91| 亚洲日本欧美| 午夜一区在线| 欧美破处大片在线视频| 欧美视频亚洲视频| 狠狠干综合网| 亚洲视频在线一区| 欧美伊人久久| 欧美激情精品久久久| 国产精品日韩一区| 18成人免费观看视频| 亚洲网站视频| 欧美美女福利视频| 影音先锋成人资源站| 欧美一区二区三区四区在线观看地址| 欧美在线观看日本一区| 欧美黄在线观看| 亚洲另类自拍| 久久久久国产一区二区三区| 国产精品www网站| 一区二区精品国产| 欧美激情在线狂野欧美精品| 国产午夜精品美女视频明星a级| 日韩视频国产视频| 欧美成ee人免费视频| 在线精品视频一区二区| 亚洲欧美日韩国产综合| 国产精品ⅴa在线观看h| 99在线精品视频| 国产精品成人观看视频免费| 日韩一级大片| 国产精品免费视频观看| 性18欧美另类| 亚洲高清在线观看一区| 蜜桃视频一区| 欧美呦呦网站| 亚洲福利在线看| 久久九九99视频| 国产一区二区精品丝袜| 久久er精品视频| 国产一区二区三区成人欧美日韩在线观看 | 亚洲国产婷婷| 欧美日韩国产不卡在线看| 亚洲欧美日韩国产中文| 国产一区二区在线观看免费| 久久久久久婷| 亚洲日韩欧美视频| 亚洲成人自拍视频| 免费欧美视频| 香蕉尹人综合在线观看| 亚洲激情图片小说视频| 国产精品乱看| 欧美日韩在线视频一区二区| 午夜精品短视频| 亚洲一区二区毛片| 99在线观看免费视频精品观看| 国产一区二区三区在线观看免费| 欧美日韩日日骚| 欧美激情一二三区| 久久久久欧美精品| 欧美一区二区视频在线观看2020 | 国产欧美精品日韩| 亚洲女同在线| 亚洲国产日韩在线| 欧美日韩美女在线| 亚洲欧美综合v| 国产免费观看久久| 亚洲欧美国产一区二区三区| 久久亚洲视频| 亚洲国语精品自产拍在线观看| 在线播放日韩欧美| 黄色资源网久久资源365| 日韩写真视频在线观看| 欧美精选在线| 在线观看欧美成人| 一区二区亚洲精品| 亚洲免费视频一区二区| 在线欧美影院|