Node.js非同步程式設計~超級詳細哦
下面是對Node.js非同步程式設計的整理,希望可以幫助到有需要的小夥伴~
同步API,非同步API
同步API:只有當API執行完成後,才能繼續執行下一個API
非同步API:當前API的執行不會阻塞後續程式碼的執行
// 同步程式設計
/*
console.log("before");
console.log("after");
// before
// after
*/
// 非同步程式設計
console.log('before');
setTimeout(
() => {
console.log('last')
},2000);
console.log('after');
/*
before
after
last
// before執行後,2秒鐘後再執行last,在這2秒鐘的時間裡after執行了
*/
同步API,非同步API的區別
獲取返回值的方式不同
同步API可以從返回值中拿到API執行的結果
非同步API必須通過回撥函式拿到非同步操作的執行結果
通過回撥函式獲取非同步函式的返回值
回撥函式:
別人呼叫自己定義的函式
// 回撥函式的定義
function getData (callback) {}
// 回撥函式的呼叫
getData ( ()=>{} );// getData()裡面的實參()=>{} 對應的是 callback形參;即在getData()函式內部呼叫了()=>{}函式
通過回撥函式獲取非同步函式的返回值示例:
/* function getMsg () {
setTimeout(function () {
return {
msg:'hello node.js'
}
},2000)
}
const msg = getMsg();
console.log(msg); // undefined
// 2秒後才可以執行定時器裡面的內容
// 所以返回值是函式的預設返回值undefined */
// 可以通過回撥函式獲取到非同步操作的執行結果
function getMsg (callback) {
setTimeout(function () {
callback({
msg:'hello node.js'
})
},2000)
}
getMsg(function (data){
console.log(data); // { msg: 'hello node.js' }
})
程式碼執行順序不同
Node.js從上而下依次執行程式碼
遇到同步API就拿到同步程式碼執行區去執行
遇到非同步API就拿到非同步程式碼執行區,但是不會執行非同步程式碼,
當所有的同步程式碼執行完畢後,再到非同步程式碼執行區依次執行程式碼
當非同步程式碼執行完畢後,系統會去回撥函式佇列中找非同步API對應的回撥函式,把回撥函式放到同步程式碼執行去區執行
同步API從上到下依次執行,前面程式碼會阻塞後面程式碼的執行
for (var i=0;i<10;i++) {
console.log(i)
}
console.log("迴圈外")
// 0 1 2 3 4 5 6 7 8 9 迴圈外
非同步API不會等待API執行完成後再向下執行程式碼
console.log('程式碼開始執行')
setTimeout(function(){
console.log('2s後執行')
},2000)
setTimeout(function(){
console.log('0s後執行')
})
console.log('程式碼結束執行')
/* 程式碼開始執行
程式碼結束執行
0s後執行
2s後執行 */
Node.js中的非同步API
非同步程式設計的返回結果是通過回撥函式獲取的
在非同步程式設計中,前面程式碼的執行不會阻礙後面程式碼的執行,但是有時候後面程式碼的執行會依賴前面程式碼的執行結果,這時可以通過多個回撥函式來完成。
讀取檔案就是通過回撥函式返回結果的,如果依次讀取多個檔案,就需要多次呼叫回撥函式
示例如下:
// 依次讀取1.txt、 2.txt 、 3.txt檔案
// 匯入檔案模組
const fs = require('fs');
// 讀取檔案
fs.readFile('./1.txt','utf8',(err,result1) => {
console.log(result1)
fs.readFile('./2.txt','utf8',(err,result2) => {
console.log(result2)
fs.readFile('./3.txt','utf8',(err,result3) => {
console.log(result3)
})
})
})
/*
// 結果:
1
2
3
*/
如果需要寫很多個回撥函式的話,就會造成回撥地獄,promise可以解決回撥地獄問題。
Promise
Promise出現的目的是解決Node.js非同步程式設計中回撥地獄的問題。
Promise是一個建構函式
Promise語法
let promise = new Promise((resolve,reject) => {
setTimeout ( () => {
if (true) {
resolve({name:'張三'})
} else {
reject('失敗了')
}
},2000)
})
promise.then(result => console.log(result)); // {name:'張三'}
.catch(error => console.log(error)); // 失敗了
- resolve:將非同步API的執行結果傳遞到整個Promise的外面(resolve是一個方法)
- reject:如果非同步API執行失敗,就把失敗的結果傳遞到整個Promise的外面 (reject是一個方法)
通過Promise物件的then方法獲取到非同步的執行結果。
通過Promise解決回撥地獄
// 依次讀取1.txt、 2.txt 、 3.txt檔案
// 匯入檔案模組
const fs = require('fs');
const { resolve } = require('path');
// 讀取檔案
/* fs.readFile('./1.txt','utf8',(err,result1) => {
console.log(result1)
fs.readFile('./2.txt','utf8',(err,result2) => {
console.log(result2)
fs.readFile('./3.txt','utf8',(err,result3) => {
console.log(result3)
})
})
}) */
function p1() {
return new Promise((resolve,reject) => {
fs.readFile('./1.txt','utf8',(err,result) => {
resolve(result)
})
})
}
function p2(){
return new Promise((resolve,reject) => {
fs.readFile('./2.txt','utf8',(err,result) => {
resolve(result);
})
})
}
function p3(){
return new Promise((resolve,reject) => {
fs.readFile('./3.txt','utf8',(err,result) => {
resolve(result);
})
})
}
p1().then((r1) => {
console.log(r1);
return p2();
})
.then((r2) => {
console.log(r2);
return p3();
})
.then((r3) => {
console.log(r3);
})
// 相當於
/* p1().then((r1) => {
console.log(r1);
});
p2().then((r2) => {
console.log(r2);
});
p3().then((r3) => {
console.log(r3);
}); */
/*
// 結果:
1
2
3
*/
非同步函式
使用Promise可以解決回撥地獄的問題,但是會產生程式碼冗餘,可以使用ES 7提供的回撥函式解決回撥地獄的問題並且程式碼更加簡單明瞭。
非同步函式是非同步程式設計語法的終極解決方案,它可以讓我們將非同步程式碼寫成同步的形式,讓程式碼不再有回撥函式巢狀,使程式碼變得清晰明瞭。
const fn = async () => {};
async關鍵字:
- 普通函式定義前加async關鍵字普通函式變成非同步函式
- 非同步函式預設返回promise物件
- 在非同步函式內部使用return關鍵字進行結果返回,結果會被包裹在promise物件中
- return關鍵字代替了resolve方法
- 在非同步函式內部使用throw關鍵字丟擲程式異常
- 呼叫非同步函式再鏈式呼叫then方法獲取非同步函式執行結果
- 呼叫非同步函式再鏈式呼叫catch方法獲取非同步函式執行的錯誤資訊
await關鍵字:
- await關鍵字只能出現在非同步函式中
- await promise ;await後面只能寫promise物件寫其他型別的API是不可以的
- await關鍵字可是暫停非同步函式向下執行直到promise返回結果
示例:
const fs = require('fs');
// fs中readFile()方法的返回結果不是Promise型別的,不能使用非同步函式中的await關鍵字
// uitl模組的promisify()方法可以將返回的結果改為Primise型別
// 沒有呼叫promisify方法,沒有寫promisify()
// 改在現有非同步函式的API,讓其返回promise物件,從而支援非同步函式語法
const promisify = require('util').promisify;
// 呼叫了promisify()方法,但沒有呼叫readFile()方法
// 呼叫promisify方法改造現有非同步API,讓其返回promise物件
const readFile = promisify(fs.readFile);
async function run() {
// 呼叫readFile()方法,該方法的返回結果回改成promise型別
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
end~
對Node.js非同步程式設計的介紹到這裡就結束啦~
希望可以對你有所幫助~
如果有錯誤,請大佬指正,萬分感謝!
相關文章
- shell程式設計-sed命令詳解(超詳細)程式設計
- Node.js非同步程式設計Node.js非同步程式設計
- iOS超級超級詳細介紹GCDiOSGC
- 超級程式設計師程式設計師
- 超級詳細Tcpdump 的用法TCP
- 004 Rust 非同步程式設計,async await 的詳細用法Rust非同步程式設計AI
- 關於詳細設計/程式碼的同步問題--請教
- python 網路程式設計----非阻塞或非同步程式設計Python程式設計非同步
- Go Web 程式設計--超詳細的模板庫應用指南GoWeb程式設計
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- SVG基礎教程(超級詳細)SVG
- (轉)超級詳細Tcpdump 的用法TCP
- 超級詳細Tcpdump 的用法(轉)TCP
- Spring AOP全面詳解(超級詳細)Spring
- Java註解最全詳解(超級詳細)Java
- Java中的多執行緒程式設計(超詳細總結)Java執行緒程式設計
- Socket程式設計中的同步、非同步、阻塞和非阻塞(轉)程式設計非同步
- Flutter非同步程式設計詳解Flutter非同步程式設計
- Node.js 非同步程式設計之 Callback介紹Node.js非同步程式設計
- 超級程式設計師神話程式設計師
- HTML 超級連結詳細講解HTML
- 超級詳細的tcpdump用法介紹TCP
- Java網路程式設計和NIO詳解5:Java 非阻塞 IO 和非同步 IOJava程式設計非同步
- python超程式設計詳解(3)Python程式設計
- python超程式設計詳解(4)Python程式設計
- python超程式設計詳解(2)Python程式設計
- Android Studio安裝教程(超級詳細)Android
- 超級詳細的react筆記(三)jsxReact筆記JS
- 看起來很適合程式設計師哦程式設計師
- 【進階之路】併發程式設計(三)-非阻塞同步機制程式設計
- Github上傳程式碼超詳細教程Github
- java程式設計師|超詳細面經(四面一總結),助你逆襲!Java程式設計師
- 【Java併發程式設計】面試常考的ThreadLocal,超詳細原始碼學習Java程式設計面試thread原始碼
- 阿里P8面試官:如何設計一個扛住千萬級併發的架構(超級詳細)-續阿里面試架構
- 世界級大牛對程式設計師超實用的程式設計箴言(上)程式設計師箴言
- 世界級大牛對程式設計師超實用的程式設計箴言(下)程式設計師箴言
- 小程式分享模組超級詳解
- 【超級經典】程式設計師裝B指南程式設計師