03.請求響應(yīng)原理及HTTP協(xié)議.5. Node.js異步編程

5. Node.js異步編程

5.1 同步API,異步API

// 路徑拼接
 const public =path.join(__dirname,'public');
 // 請求地址解析
 const urlObj =url.parse(req.url);
 // 讀取文件
 fs.readFile('./demo.txt','utf8',(err,result) => {
    console.log(result);
 });

同步API:只有當(dāng)前API執(zhí)行完成后往声,才能繼續(xù)執(zhí)行下一個API

console.log('before'); 
console.log('after');
//before
//last

異步API:當(dāng)前API的執(zhí)行不會阻塞后續(xù)代碼的執(zhí)行

console.log('before');
setTimeout(
  ()=> {console.log('last');
}, 2000);
console.log('after');
//before
//after
//last

5.2 同步API,異步API的區(qū)別(獲取返回值 )

同步API可以從返回值中拿到API執(zhí)行的結(jié)果, 但是異步API是不可以的

// 同步
 function sum (n1,n2) {
      return n1 + n2;
 }
  const result = sum (10,20);
// 異步
 function getMsg () {
      setTimeout(function() {
          return { msg:'Hello Node.js'}
      },2000);
 }
 const msg =getMsg ();//undefinded

5.3 回調(diào)函數(shù)

自己定義函數(shù)讓別人去調(diào)用窿克。

//getData函數(shù)定義
 function getData (callback){}
  // getData函數(shù)調(diào)用
 getData(()=> {});

5.4 使用回調(diào)函數(shù)獲取異步API執(zhí)行結(jié)果

function getMsg (callback){
   setTimeout(function () {
        callback({ msg:'Hello Node.js'})
   }, 2000);
}
getMsg (function(msg){
   console.log(msg);//{ msg:'Hello Node.js'}
});

5.5 同步API,異步API的區(qū)別(代碼執(zhí)行順序)

同步API從上到下依次執(zhí)行朱盐,前面代碼會阻塞后面代碼的執(zhí)行

for (var i = 0;i < 100000;i++) {
   console.log(i);
}
console.log('for循環(huán)后面的代碼');

異步API不會等待API執(zhí)行完成后再向下執(zhí)行代碼

console.log('代碼開始執(zhí)行');
setTimeout(() => {console.log('2秒后執(zhí)行的代碼')},2000);
setTimeout(() => {console.log('"0秒"后執(zhí)行的代碼')},0);
console.log('代碼結(jié)束執(zhí)行');
//代碼開始執(zhí)行
//代碼結(jié)束執(zhí)行
//"0秒"后執(zhí)行的代碼
//2秒后執(zhí)行的代碼

5.6 代碼執(zhí)行順序分析

console.log('代碼開始執(zhí)行');
setTimeout(() => {
   console.log('2秒后執(zhí)行的代碼');
}, 2000);
setTimeout(() => {
   console.log('"0秒"后執(zhí)行的代碼');
}, 0);
console.log('代碼結(jié)束執(zhí)行');
image

5.7 Node.js中的異步API

fs.readFile('./demo.txt',(err,result) => {});
var server =http.createServer();
 server.on('request',(req,res) => {});

如果異步API后面代碼的執(zhí)行依賴當(dāng)前異步API的執(zhí)行結(jié)果薛训,但實際上后續(xù)代碼在執(zhí)行的時候異步API還沒有返回結(jié)果苍匆,這個問題要怎么解決呢罢维?

fs.readFile('./demo.txt',(err,result) => {});
console.log('文件讀取結(jié)果');

需求:依次讀取A文件、B文件绢记、C文件

const fs=require('fs');
//回調(diào)地獄
fs.readFile('./1.txt','utf8',(err,result1)=>{
       console.log(result1);
       fs.readFile('./2.txt','utf8',(err,result2)=>{
              console(result2);
              fs.readFile('./3.txt','utf8',(err,result3)=>{
                     console(result3);
              });
       });
});

5.8 Promise

Promise出現(xiàn)的目的是解決Node.js異步編程中回調(diào)地獄的問題。

let promise =new Promise((resolve,reject) => {
   setTimeout(() => {
        if(true){
            resolve({name:'張三'})//成功讀取執(zhí)行
        }else {
            reject('失敗了')//失敗讀取執(zhí)行
        }
   }, 2000);
});
promise.then(result=> console.log(result)); // {name: '張三'}//resolve傳參進入then執(zhí)行回調(diào)函數(shù)
       .catch(error => console.log(error)); // 失敗了//reject傳參進入catch執(zhí)行回調(diào)函數(shù)

5.9 異步函數(shù)

異步函數(shù)是異步編程語法的終極解決方案正卧,它可以讓我們將異步代碼寫成同步的形式蠢熄,讓代碼不再有回調(diào)函數(shù)嵌套,使代碼變得清晰明了炉旷。

const fn =async () => {};
async function fn () {}

async關(guān)鍵字
1. 普通函數(shù)定義前加async關(guān)鍵字 普通函數(shù)變成異步函數(shù)
2. 異步函數(shù)默認(rèn)返回promise對象
3. 在異步函數(shù)內(nèi)部使用return關(guān)鍵字進行結(jié)果返回 結(jié)果會被包裹的promise對象中 return關(guān)鍵字代替了resolve方法
4. 在異步函數(shù)內(nèi)部使用throw關(guān)鍵字拋出程序異常
5. 調(diào)用異步函數(shù)再鏈?zhǔn)秸{(diào)用then方法獲取異步函數(shù)執(zhí)行結(jié)果
6. 調(diào)用異步函數(shù)再鏈?zhǔn)秸{(diào)用catch方法獲取異步函數(shù)執(zhí)行的錯誤信息

await關(guān)鍵字
1. await關(guān)鍵字只能出現(xiàn)在異步函數(shù)中
2. await promise await后面只能寫promise對象 寫其他類型的API是不不可以的
3. await關(guān)鍵字可是暫停異步函數(shù)向下執(zhí)行直到promise返回結(jié)果

const fs = require('fs');
// 改造現(xiàn)有異步函數(shù)api 讓其返回promise對象 從而支持異步函數(shù)語法
const promisify = require('util').promisify;
// 調(diào)用promisify方法改造現(xiàn)有異步API 讓其返回promise對象
const readFile = promisify(fs.readFile);
async function run () {
    let r1 = await readFile('./1.txt', 'utf8')
    let r2 = await readFile('./2.txt', 'utf8')
    let r3 = await readFile('./3.txt', 'utf8')
    console.log(r1)
    console.log(r2)
    console.log(r3)
}
run();
//1
//2
//3
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末签孔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子窘行,更是在濱河造成了極大的恐慌饥追,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罐盔,死亡現(xiàn)場離奇詭異但绕,居然都是意外死亡,警方通過查閱死者的電腦和手機惶看,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門捏顺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人碳竟,你說我怎么就攤上這事草丧。” “怎么了莹桅?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵昌执,是天一觀的道長。 經(jīng)常有香客問我诈泼,道長懂拾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任铐达,我火速辦了婚禮岖赋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瓮孙。我一直安慰自己唐断,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布杭抠。 她就那樣靜靜地躺著脸甘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪偏灿。 梳的紋絲不亂的頭發(fā)上丹诀,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音,去河邊找鬼铆遭。 笑死硝桩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的枚荣。 我是一名探鬼主播碗脊,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼棍弄!你這毒婦竟也來了望薄?” 一聲冷哼從身側(cè)響起疟游,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤呼畸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后颁虐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛮原,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年另绩,在試婚紗的時候發(fā)現(xiàn)自己被綠了儒陨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡笋籽,死狀恐怖蹦漠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情车海,我是刑警寧澤笛园,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站侍芝,受9級特大地震影響研铆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜州叠,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一棵红、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咧栗,春花似錦逆甜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至可岂,卻和暖如春错敢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工稚茅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纸淮,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓亚享,卻偏偏與公主長得像咽块,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子欺税,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容