天天看點

解決回調地獄問題

比如我們現在有個讀取檔案的需求,那麼用nodejs,剛開始我們的代碼會這麼寫

var fs=require('fs');
var path=require('path');


function readFile(fpath){
  fs.readFile(fpath,'utf-8',(err,data)=>{
    if(err) throw err;
    return data;
  })
}


let res=readFile('App.vue');
//這裡列印為undefined 因為fs.readFile是異步的,主線程在遇到異步函數時,會将異步任務放到隊列中,然後
//繼續執行,是以這裡得到undefined
console.log(res);
           

解決思路1:利用回調函數,擷取異步結果

function readFile(fpath,callback){
  fs.readFile(fpath,'utf-8',(err,data)=>{
    if(err) throw err;
    throw new Error('er hui');
    callback(data);
  })
}
//但這裡又存在一個問題,如果這個函數經常發生異常,這樣的話,通過回調還是拿不到結果的,
//我們應該将處理的結果告訴給調用者,由調用者決定要如果處理結果,包括異常結果
readFile('App.vue',result=>{
  console.log(result)
});


改進如下,将回調函數定義成有兩個參數:
function readFile(fpath,callback){
  fs.readFile(fpath,'utf-8',(err,data)=>{
    if(err) callback(err);
    callback(null,data);
  })
}
//但這裡又存在一個問題,如果這個函數經常發生異常,這樣的話,通過回調還是拿不到結果的,
//我們應該将處理的結果告訴給調用者,由調用者決定要如果處理結果,包括異常結果
readFile('App.vue2',(err,result)=>{
  if(err) throw err;
  console.log(result)
});


//改進思路3
//我們這樣寫是沒問題了,但對于初學者來說可能有點不好了解,這裡我們可以規定指定的函數來處理成功的結果和異常結果
function readFile(fpath,succ,fail){
  fs.readFile(fpath,'utf-8',(err,data)=>{
    if(err) return fail(err);
    succ(data);
  })
}
readFile('App.vue',function (data) {
  console.log('succ');
  console.log(data);
},function (err) {
  console.log('fail');
  console.log(err);
});
           

假設有個需求,按順序讀取檔案。那麼我們可能會這樣寫

readFile('1.txt',function (data) {
  console.log(data);
  readFile('2.js',function (data) {
    console.log(data);
    readFile('3.js',function (data) {
      console.log(data);
    });
  });
});
這就是一個典型的回調地獄問題,
解決辦法:使用ES6 的 Promise 


//1.Promise 是一個構造函數,既然是構造函數,那麼我們就可以 new Promise() 
得到一個 Promise 執行個體
//2.在Promise 上,有兩個函數,分别叫 resolve(成功後的回調),和 reject(失敗後的回調)
3,在Promise 構造函數的 prototype 屬性上,有個.then 方法,也就是說隻要
Promise 構造函數建立的執行個體,都可以通路到 .then() 方法
4,Promise 表示一個異步操作,每當我們 new 一個 Promise 的執行個體,這個執行個體就表示一個
具體的異步操作
5,既然Promise 建立的執行個體,是一個異步操作,那麼這個異步操作的結果,隻有兩種狀态
5.1 異步成功了
5.2 異步失敗了
5.3 由于Promise 的執行個體,是一個異步操作,是以内部拿到操作的結果後,無法使用return
把操作的結果傳回給調用者,這時候,隻能使用回調函數的形式,把成功或失敗的結果傳回
給調用者

每當new 一個 Promise 執行個體的時候,會立即執行這個異步操作中的代碼
注意:通過.then 指定回調函數的時候,成功的回調函數必須傳。但是失敗的函數的回調
可以不傳

當第一個回調報錯時,後面的異步操作都不執行了,當需要第一個異步操作不影響後續回調
,需要傳入異常處理函數
當後續的Promise 操作依賴于前面的Promise 操作的結果,那麼可以使用catch 将異常抓住
也就是說,目前面任意一個Promise 執行出錯,都會被catch 抓住

function readFile(fpath){
  var promise=new Promise(function (resolve,reject) {
    fs.readFile(fpath,'utf-8',(err,data)=>{
      if(err) return reject(err);
      resolve(data);
    })
  });
 return promise;
}

var promise=readFile('Ap2p.vue');
promise.then(function (data) {
  console.log('2111')
  console.log(data)
  return readFile('main.js')
}).then(function (data) {
  console.log('222')
  return readFile('fs.js')
}).then(function (data) {
  console.log('333')
  console.log(data)
}).catch(function (err) {
  console.log('err===============')
  console.log(err)
});



           

補充:console.dir() 可以顯示一個對象所有的屬性和方法。

版權聲明:本文為CSDN部落客「weixin_34037515」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/weixin_34037515/article/details/92392476