1. 程式人生 > >js進階四(js回撥、promise、promise巢狀、異常處理、jquery使用promise)

js進階四(js回撥、promise、promise巢狀、異常處理、jquery使用promise)

同步讀取

我們來看一個從檔案讀取內容的例子,以下是這個例子的目錄結構 在這裡插入圖片描述

我們看下promiser.js的程式碼如下:

const fs = require("fs")
const path = require("path")

function getFileByPath(fPath){
    fs.readFile(fPath,'utf-8',(err,dataStr) => {
        if (err) throw err
        console.log("datastr",dataStr)

        return dataStr
    })
}

var ret = getFileByPath(path.join(__dirname,'./files/1.txt'))

console.log("ret",ret)

結果我們看下log輸出如下:

zhiliaodeMBP:promise zhiliao$ node ./promiser.js
ret undefined
datastr 1231

在JavaScript的世界中,所有程式碼都是單執行緒執行的,因為讀取檔案是耗時操作,所以執行到getFileByPath時,還沒有讀取完畢檔案內容會輸出undefined

回撥函式

由於這個“缺陷”,導致JavaScript的所有網路操作,瀏覽器事件,都必須是非同步執行。非同步執行可以用回撥函式實現:

const fs = require("fs")
const path = require("path")

function getFileByPath(fPath,callback){
    fs.readFile(fPath,'utf-8',(err,dataStr) => {
        if (err) throw err

        callback(dataStr)
    })
}

getFileByPath(path.join(__dirname,'./files/1.txt'),function(data){
    console.info(data)
})

我們看下結果

zhiliaodeMBP:promise zhiliao$ node ./promiser.js
1231

回撥機制處理異常

上述例子程式碼不完善,如果讀取檔案內容失敗,也就是出現異常,我們怎麼處理?

const fs = require("fs")
const path = require("path")

function getFileByPath(fPath,callback,errCallBack){
    fs.readFile(fPath,'utf-8',(err,dataStr) => {
        if (err) return errCallBack(err)
        callback(dataStr)
    })
}

getFileByPath(path.join(__dirname,'./files/1.txt'),function(data){
    console.info(data)
},function(err){
    if(err) return console.info(err.message)
})


我們看下測試結果,我們看到是捕獲了異常:

zhiliaodeMBP:promise zhiliao$ node ./promiser.js
ENOENT: no such file or directory, open '/Users/zhiliao/zhiliao/vue/promise/files/11.txt'

promise

以上是我們讀取一個檔案內容,如果我們連續讀取多個檔案內容呢?我們可以用一種迴圈巢狀的方式,但是巢狀的方法過於繁瑣,我們可以利用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 狀態1: 非同步執行成功了,需要在內部呼叫 成功的回撥函式 resolve 把結果返回給呼叫者; 5.2 狀態2: 非同步執行失敗了,需要在內部呼叫 失敗的回撥函式 reject 把結果返回給呼叫者; 5.3 由於 Promise 的例項,是一個非同步操作,所以,內部拿到 操作的結果後,無法使用 return 把操作的結果返回給呼叫者; 這時候,只能使用回撥函式的形式,來把 成功 或 失敗的結果,返回給呼叫者;
  6. 我們可以在 new 出來的 Promise 例項上,呼叫 .then() 方法,【預先】 為 這個 Promise 非同步操作,指定 成功(resolve) 和 失敗(reject) 回撥函式;
const fs = require("fs")
const path = require("path")

function getFileByPath(fpath){
    var promise = new Promise(function(resolve,reject){

        fs.readFile(fpath,"utf-8",(err,dataStr)=>{
            if(err) return reject(err)
            resolve(dataStr)
        })
    })

    return promise
}

var promise = getFileByPath('./files/1.txt')

promise.then(function(data){
    console.log(data,"~~~")
},function(err){
    console.log(err.message,">>>>")
})

我們看下測試效果如下:

zhiliaodeMBP:promise zhiliao$ node ./promiser.js
1231 ~~~

我們簡單梳理下這個promise例子的執行過程: 程式執行 1.首先載入getFileByPath進記憶體, 2.然後getFileByPath('./files/1.txt')呼叫該方法,執行getFileByPath方法內程式碼,執行readFile操作,這裡是耗時操作 3.返回promise物件 4.promise.then傳遞迴調函式 5.等待readFile執行完畢,執行回撥函式

promise巢狀

我們還可以通過如下的方式實現批量讀取檔案內容 只需要在第一次讀取完畢後,進行返回一個promise,然後在繼續.then操作即可


function getFileByPath(fpath){
    var promise = new Promise(function(resolve,reject){

        fs.readFile(fpath,"utf-8",(err,dataStr)=>{
            if(err) return reject(err)
            resolve(dataStr)
        })
    })

    return promise
}

var promise1 = getFileByPath('./files/1.txt')


promise1.then(function(data){
    console.log(data,"~~~")
    var promise2 = getFileByPath('./files/2.txt')
    return promise2
},function(err){
    console.log(err.message,">>>>")
})
.then(function(data){
    console.log(data,"~~~")
},function(err){
    console.log(err.message,">>>>")
})

捕獲異常

方法一

如果連續讀取2個檔案的內容,如果第一個檔案讀取失敗,那麼我們不應該停止程式,應該讓他繼續讀取第二個檔案,這就需要我們自己收到在第一次讀取失敗時候,做失敗處理

const fs = require("fs")
const path = require("path")

function getFileByPath(fpath){
    var promise = new Promise(function(resolve,reject){

        fs.readFile(fpath,"utf-8",(err,dataStr)=>{
            if(err) return reject(err)
            resolve(dataStr)
        })
    })

    return promise
}

var promise1 = getFileByPath('./files/1但是.txt')


promise1.then(function(data){
    console.log(data,"~~成功~")
    return getFileByPath('./files/2.txt')
},function(err){
    console.log(err,"~~失敗~")
    return getFileByPath('./files/2.txt')
})
.then(function(data){
    console.log(data,"~~~")
},function(err){
    console.log(err.message,">>>>")
})


測試結果如下:

zhiliaodeMBP:promise zhiliao$ node ./promiser.js{ [Error: ENOENT: no such file or directory, open './files/1但是.txt']
  errno: -2,  code: 'ENOENT',  syscall: 'open',
  path: './files/1但是.txt' } '~~失敗~'wewr ~~~

方法二

只要有任何一個then語句出錯,就終止全部語句 我們還可以利用catch語句塊,不要在.then 裡面去處理錯誤異常,而是需要在外面直接catch

const fs = require("fs")
const path = require("path")


function getFileByPath(fpath){
    var promise = new Promise(function(resolve,reject){

        fs.readFile(fpath,"utf-8",(err,dataStr)=>{
            if(err) return reject(err)
            resolve(dataStr)
        })
    })

    return promise
}

var promise1 = getFileByPath('./files/1.txt')


promise1.then(function(data){
    console.log(data,"~~成功~")
    return getFileByPath('./files/2等待.txt')
})
.then(function(data){
    console.log(data,"~~~")
})

.catch(function (err) { // catch 的作用: 如果前面有任何的 Promise 執行失敗,則立即終止所有 promise 的執行,並 馬上進入 catch 去處理 Promise中 丟擲的異常;
    console.log('這處理方式:' + err.message)
  })

測試效果如下:

1231 ~~成功~
這是自己的處理方式:ENOENT: no such file or directory, open './files/2等待.txt'
zhiliaodeMBP:promise zhiliao$

jquery中使用promise

在這裡插入圖片描述 我們先來看一個原始的ajax請求 data.json

{
    "name":"safly",
    "age":30
}
<script src="./webpack_vue/node_modules/jquery/dist/jquery.min.js"></script>
<body>
<input type="button" value="getdata" id="btn">
<script>
$(function(){
  $("#btn").click(function(){
    $.ajax({
      url:"./data.json",
      type:"get",
      dataType:"json",
      success:function(data){
         console.log(data)
      }
    })
  })
})

</script>
</body>
</html>

我們來使用下jquery裡面的promise操作

$(function(){
  $("#btn").click(function(){
    $.ajax({
      url:"./data.json",
      type:"get",
      dataType:"json",
      // success:function(data){
      //    console.log(data)
      // }
    }).then(function(data){
        console.log(data)
    })
  })
})

也可以輸出同樣的結果