目錄
一、前言
先看一個例子:
const fs = require('fs')
//a.txt文件內容是aaa
fs.readFile('a.txt', 'utf8', function(err, data){
console.log(data);
})
console.log("123456");
這個例子的預期功能,就是讀取並輸出a.txt文件的內容"aaa",然後再輸出“123456”,然而看輸出卻與預期不一樣:
這就引出了異步和回調的概念。
二、異步與回調
nodejs是一個單線程函數,主線程在執行的時候,一旦發生了異步處理(文件讀寫、網絡請求、定時任務、讀取數據庫等),一方面,js會讓操作系統相關部件去處理這些請求,另一方面,它會繼續執行後面的代碼,這就是異步。
然後,當js讓操作系統相關部件去處理這些請求,當這些請求有返回數據時(比如網絡請求返回數據了),js就會調用相應的事件對象裏的處理函數,這個處理函數,就是回調函數。
通俗的講,就是js不管你有沒處理完異步函數,就開始往下走了,除非異步函數處理的速度極快極快,才能出現“按代碼順序執行”的情況。
三、解決方案
①把需後面執行的程序,放到異步函數內,例如如下:
const fs = require('fs')
//a.txt文件內容是aaa
fs.readFile('a.txt', 'utf8', function(err, data){
console.log(data);
console.log("123456");
})
這樣做可以解決問題,但是會引入一個問題,就是如果嵌套多了,代碼會不美觀,這種寫法又稱爲“回調地獄”
②使用Promise
Promise是在ES6的標準中出現的,也就是nodejs v8.5.0以上版本,低於這個版本不能使用(版本查看命令:node -v)
Promise構造函數接受一個函數作爲參數,該函數的兩個參數分別是resolve和reject,它們是兩個函數,由js引擎內部提供,不用自己部署。
resolved函數,在異步操作成功時調用,並將異步操作的結果,作爲參數傳遞出去;reject函數,在異步操作失敗時調用,並將異步操作報出的錯誤,作爲參數傳遞出去。
const fs = require('fs')
const aPromise = new Promise((resolve, reject) => {
fs.readFile('a.txt', 'utf8', function(err, data){
if (err) return reject(err)
resolve(data)
})
})
const bPromise = new Promise((resolve, reject) => {
resolve("123456");
})
//then的作用執行Promise並返回結果
//這裏可以理解爲:aPromise.then(執行結果),return bPromise, bPromise.then(執行結果)
aPromise
.then(Content1 => {
console.log(Content1);
return bPromise
})
.then(Content2 => {
console.log(Content2);
})