一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - node.js - 一文秒懂nodejs中的異步編程

一文秒懂nodejs中的異步編程

2022-01-10 16:44flydean程序那些事 node.js

這篇文章主要介紹了深入理解nodejs中的異步編程,本文給大家介紹的非常想詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

文章目錄 簡介同步異步和阻塞非阻塞javascript中的回調回調函數的錯誤處理回調地獄 ES6中的Promise什么是PromisePromise的特點Promise的優(yōu)點Promise的缺點Promise的用法Promise的執(zhí)行順序 async和awaitasync的執(zhí)行順序async的特點 總結

簡介

因為javascript默認情況下是單線程的,這意味著代碼不能創(chuàng)建新的線程來并行執(zhí)行。但是對于最開始在瀏覽器中運行的javascript來說,單線程的同步執(zhí)行環(huán)境顯然無法滿足頁面點擊,鼠標移動這些響應用戶的功能。于是瀏覽器實現了一組API,可以讓javascript以回調的方式來異步響應頁面的請求事件。

更進一步,nodejs引入了非阻塞的 I/O ,從而將異步的概念擴展到了文件訪問、網絡調用等。

今天,我們將會深入的探討一下各種異步編程的優(yōu)缺點和發(fā)展趨勢。

同步異步和阻塞非阻塞

在討論nodejs的異步編程之前,讓我們來討論一個比較容易混淆的概念,那就是同步,異步,阻塞和非阻塞。

所謂阻塞和非阻塞是指進程或者線程在進行操作或者數據讀寫的時候,是否需要等待,在等待的過程中能否進行其他的操作。

如果需要等待,并且等待過程中線程或進程無法進行其他操作,只能傻傻的等待,那么我們就說這個操作是阻塞的。

反之,如果進程或者線程在進行操作或者數據讀寫的過程中,還可以進行其他的操作,那么我們就說這個操作是非阻塞的。

同步和異步,是指訪問數據的方式,同步是指需要主動讀取數據,這個讀取過程可能是阻塞或者是非阻塞的。而異步是指并不需要主動去讀取數據,是被動的通知。

很明顯,javascript中的回調是一個被動的通知,我們可以稱之為異步調用。

javascript中的回調

javascript中的回調是異步編程的一個非常典型的例子:

?
1
2
3
document.getElementById('button').addEventListener('click', () => {
 console.log('button clicked!');
})

上面的代碼中,我們?yōu)閎utton添加了一個click事件監(jiān)聽器,如果監(jiān)聽到了click事件,則會出發(fā)回調函數,輸出相應的信息。

回調函數就是一個普通的函數,只不過它被作為參數傳遞給了addEventListener,并且只有事件觸發(fā)的時候才會被調用。

上篇文章我們講到的setTimeout和setInterval實際上都是異步的回調函數。

回調函數的錯誤處理

在nodejs中怎么處理回調的錯誤信息呢?nodejs采用了一個非常巧妙的辦法,在nodejs中,任何回調函數中的第一個參數為錯誤對象,我們可以通過判斷這個錯誤對象的存在與否,來進行相應的錯誤處理。

?
1
2
3
4
5
6
7
8
9
10
fs.readFile('/文件.json', (err, data) => {
 if (err !== null) {
 //處理錯誤
 console.log(err)
 return
 }
 
 //沒有錯誤,則處理數據。
 console.log(data)
})

回調地獄

javascript的回調雖然非常的優(yōu)秀,它有效的解決了同步處理的問題。但是遺憾的是,如果我們需要依賴回調函數的返回值來進行下一步的操作的時候,就會陷入這個回調地獄。

叫回調地獄有點夸張了,但是也是從一方面反映了回調函數所存在的問題。

?
1
2
3
4
5
6
7
fs.readFile('/a.json', (err, data) => {
 if (err !== null) {
 fs.readFile('/b.json',(err,data) =>{
  //callback inside callback
 })
 }
})

怎么解決呢?

別怕ES6引入了Promise,ES2017引入了Async/Await都可以解決這個問題。

ES6中的Promise

什么是Promise

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

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

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

Promise的特點

Promise有兩個特點:

對象的狀態(tài)不受外界影響。

Promise對象代表一個異步操作,有三種狀態(tài):Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和Rejected(已失敗)。

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

一旦狀態(tài)改變,就不會再變,任何時候都可以得到這個結果。

Promise對象的狀態(tài)改變,只有兩種可能:從Pending變?yōu)镽esolved和從Pending變?yōu)镽ejected。

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

Promise的優(yōu)點

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

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

Promise的缺點

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

Promise的用法

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

?
1
2
3
4
5
6
7
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。

?
1
2
3
4
5
promise.then(function(value) {
// success
}, function(error) {
// failure }
);

我們看一個具體的例子:

?
1
2
3
4
5
6
7
function timeout(ms){
 return new Promise(((resolve, reject) => {
  setTimeout(resolve,ms,'done');
 }))
}
 
timeout(100).then(value => console.log(value));

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

最后程序輸出done。

Promise的執(zhí)行順序

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let promise = new Promise(((resolve, reject) => {
 console.log('Step1');
 resolve();
}));
 
promise.then(() => {
 console.log('Step3');
});
 
console.log('Step2');
 
輸出:
Step1
Step2
Step3

async和await

Promise當然很好,我們將回調地獄轉換成了鏈式調用。我們用then來將多個Promise連接起來,前一個promise resolve的結果是下一個promise中then的參數。

鏈式調用有什么缺點呢?

比如我們從一個promise中,resolve了一個值,我們需要根據這個值來進行一些業(yè)務邏輯的處理。

假如這個業(yè)務邏輯很長,我們就需要在下一個then中寫很長的業(yè)務邏輯代碼。這樣讓我們的代碼看起來非常的冗余。

那么有沒有什么辦法可以直接返回promise中resolve的結果呢?

答案就是await。

當promise前面加上await的時候,調用的代碼就會停止直到 promise 被解決或被拒絕。

注意await一定要放在async函數中,我們來看一個async和await的例子:

?
1
2
3
4
5
const logAsync = () => {
 return new Promise(resolve => {
 setTimeout(() => resolve('小馬哥'), 5000)
 })
}

上面我們定義了一個logAsync函數,該函數返回一個Promise,因為該Promise內部使用了setTimeout來resolve,所以我們可以將其看成是異步的。

要是使用await得到resolve的值,我們需要將其放在一個async的函數中:

?
1
2
3
4
const doSomething = async () => {
 const resolveValue = await logAsync();
 console.log(resolveValue);
}

async的執(zhí)行順序

await實際上是去等待promise的resolve結果我們把上面的例子結合起來:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const logAsync = () => {
 return new Promise(resolve => {
  setTimeout(() => resolve('小馬哥'), 1000)
 })
}
 
const doSomething = async () => {
 const resolveValue = await logAsync();
 console.log(resolveValue);
}
 
console.log('before')
doSomething();
console.log('after')

上面的例子輸出:

before
after
小馬哥

可以看到,aysnc是異步執(zhí)行的,并且它的順序是在當前這個周期之后。

async的特點

async會讓所有后面接的函數都變成Promise,即使后面的函數沒有顯示的返回Promise。

?
1
2
3
4
5
const asyncReturn = async () => {
 return 'async return'
}
 
asyncReturn().then(console.log)

因為只有Promise才能在后面接then,我們可以看出async將一個普通的函數封裝成了一個Promise:

?
1
2
3
4
5
const asyncReturn = async () => {
 return Promise.resolve('async return')
}
 
asyncReturn().then(console.log)

總結

promise避免了回調地獄,它將callback inside callback改寫成了then的鏈式調用形式。

但是鏈式調用并不方便閱讀和調試。于是出現了async和await。

async和await將鏈式調用改成了類似程序順序執(zhí)行的語法,從而更加方便理解和調試。

我們來看一個對比,先看下使用Promise的情況:

?
1
2
3
4
5
6
7
8
9
const getUserInfo = () => {
 return fetch('/users.json') // 獲取用戶列表
 .then(response => response.json()) // 解析 JSON
 .then(users => users[0]) // 選擇第一個用戶
 .then(user => fetch(`/users/${user.name}`)) // 獲取用戶數據
 .then(userResponse => userResponse.json()) // 解析 JSON
}
 
getUserInfo()

將其改寫成async和await:

?
1
2
3
4
5
6
7
8
9
10
const getUserInfo = async () => {
 const response = await fetch('/users.json') // 獲取用戶列表
 const users = await response.json() // 解析 JSON
 const user = users[0] // 選擇第一個用戶
 const userResponse = await fetch(`/users/${user.name}`) // 獲取用戶數據
 const userData = await userResponse.json() // 解析 JSON
 return userData
}
 
getUserInfo()

可以看到業(yè)務邏輯變得更加清晰。同時,我們獲取到了很多中間值,這樣也方便我們進行調試。

到此這篇關于深入理解nodejs中的異步編程的文章就介紹到這了,更多相關nodejs異步編程內容請搜索服務器之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/superfjj/article/details/112698287

延伸 · 閱讀

精彩推薦
  • node.jsk8s node節(jié)點重新加入master集群的實現

    k8s node節(jié)點重新加入master集群的實現

    這篇文章主要介紹了k8s node節(jié)點重新加入master集群的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    Scarborought13922022-01-22
  • node.jsNode.js 中如何收集和解析命令行參數

    Node.js 中如何收集和解析命令行參數

    這篇文章主要介紹了Node.js 中如何收集和解析命令行參數,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    descire8802021-12-28
  • node.jsnodejs中使用worker_threads來創(chuàng)建新的線程的方法

    nodejs中使用worker_threads來創(chuàng)建新的線程的方法

    這篇文章主要介紹了nodejs中使用worker_threads來創(chuàng)建新的線程的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友...

    flydean程序那些事8982022-01-06
  • node.js詳解node.js創(chuàng)建一個web服務器(Server)的詳細步驟

    詳解node.js創(chuàng)建一個web服務器(Server)的詳細步驟

    這篇文章主要介紹了詳解node.js創(chuàng)建一個web服務器(Server)的詳細步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    王佳斌8952021-12-31
  • node.jsrequire加載器實現原理的深入理解

    require加載器實現原理的深入理解

    這篇文章主要給大家介紹了關于require加載器實現原理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    隱冬8462022-03-03
  • node.jsNode.js ObjectWrap 的弱引用問題

    Node.js ObjectWrap 的弱引用問題

    最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發(fā)現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。...

    編程雜技9852022-01-04
  • node.js在瀏覽器中,把 Vite 跑起來了!

    在瀏覽器中,把 Vite 跑起來了!

    大家好,我是 ssh,前幾天在推上沖浪的時候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運行起來了。這引起了我的興趣,如...

    前端從進階到入院9282022-01-11
  • node.jslinux服務器快速卸載安裝node環(huán)境(簡單上手)

    linux服務器快速卸載安裝node環(huán)境(簡單上手)

    這篇文章主要介紹了linux服務器快速卸載安裝node環(huán)境(簡單上手),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    mose-x8462022-01-22
主站蜘蛛池模板: 国产精品福利在线观看免费不卡 | 免费看黄色片的网站 | 91果冻制片厂天美传媒 | 亚洲精品视频专区 | 国产片在线看 | 免费视频精品一区二区三区 | 国产免费丝袜调教视频 | 狠狠做五月深爱婷婷天天综合 | 沉沦艳妇杨幂肉体小说 | 国产福利资源 | jzz大全部 | 任我鲁精品视频精品 | 国产成人精品一区二区 | 全黄h全肉细节文在线观看 全彩成人18h漫画 | 非洲黑人又大粗gay 非洲黑人bbwbbwbbw | 996热精品视频在线观看 | 色婷婷网 | 色综合久久最新中文字幕 | 99re8在这里只有精品23 | 奇米888在线看奇米999 | 羞羞视频污 | 免费看h片的网站 | 四虎地址8848aa4hc44四虎 四虎成人永久地址 | 四虎影剧院 | 亚洲高清中文字幕一区二区三区 | 午夜AV内射一区二区三区红桃视 | 国产精品天天看天天爽 | 办公室强行丝袜秘书啪啪 | 欧美成人福利 | 日本福利片国产午夜久久 | 午夜dj影院在线视频观看完整 | 女子监狱第二季未删减在线看 | 午夜性色一区二区三区不卡视频 | 国内精品视频免费观看 | 欧美精品国产一区二区三区 | 2020中文字幕 | 国产亚洲精品精品国产亚洲综合 | 日韩精品免费一区二区 | 日本人黄色 | 欧美成人精品第一区二区三区 | 美女露奶奶 |