成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

異步讀取文件的幾種姿勢

chinafgj / 3580人閱讀

摘要:臆想的針對讀取到的內(nèi)容進(jìn)行操作,比如打印文件內(nèi)容臆想中,讀取文件是有返回值的,將返回值,即文件內(nèi)容,賦給一個變量,然后決定對讀取到的內(nèi)容進(jìn)行相應(yīng)的操作,例如打印文件中的內(nèi)容。

臆想的
let fs = require("fs")

function readFile(filename){
    ...
}

let content = readFile("config.js")
// 針對讀取到的內(nèi)容進(jìn)行操作,比如打印文件內(nèi)容
console.log(content)

臆想中,讀取文件是有返回值的,將返回值,即文件內(nèi)容,賦給一個變量,然后決定對讀取到的內(nèi)容進(jìn)行相應(yīng)的操作,例如打印文件中的內(nèi)容。

簡而言之,臆想中,讀取文件,打印文件是相互分開的。

回調(diào)
let fs = require("fs")

function readFile(filename, callback){
    fs.readFile(filename, "utf8", (err, data) => {
        if(err){
            throw new err
        }
        callback(data)
    })
}

readFile("config.js", data => {
    console.log(data)
})

實際上,在經(jīng)常使用的回調(diào)中,讀取文件和針對文件內(nèi)容相應(yīng)的操作是在一起的,

你在要求讀取文件的同時,還要說明獲取文件內(nèi)容后干嘛

這和習(xí)慣性思維,你先把文件內(nèi)容給我,至于我怎么處理,稍后再說

Promise
let fs = require("fs")

function readFile(filename) {
    return new Promise(function (resolve) { // 這里的callback,是在run函數(shù)中傳遞的
        fs.readFile(filename, "utf8", (err, data) => {
            if (err) {
                reject(err)
            }
            resolve(data)
        })
    })
}

let content = readFile("config.js")
content.then(res => {
    console.log(res)
})
// 對比臆想中的
let content = readFile("config.js")
// 針對讀取到的內(nèi)容進(jìn)行操作,比如打印文件內(nèi)容
console.log(content)

使用Promise后,整個書寫邏輯開始和臆想中的很接近了,讀取文件和對文件內(nèi)容的操作分開了

即通過使用Promise,可以將異步的操作和對異步結(jié)果的處理,分開

來實現(xiàn)一個簡陋的假的Promise
let fs = require("fs")

function resolve(value) {
    let _self = this
    setTimeout(function () {
        _self.callbacks.forEach(function (callback) {
            callback(value);
        })
    }, 0)
    // 保證在resolve執(zhí)行之前,then方法都已經(jīng)注冊
}

class FakePromise {

    constructor(fn) {
        // fn是個函數(shù),里面包含異步,異步成功
        // Promise在new的過程中就已經(jīng)開始執(zhí)行異步代碼
        // 異步代碼執(zhí)行完觸發(fā)resolve,resolve作為異步代碼的參數(shù),它早已經(jīng)實現(xiàn)好
        this.value = null
        this.callbacks = []
        fn(resolve.bind(this))
    }

    then(onFulfilled) {
        this.callbacks.push(onFulfilled)
        return this
    }
}

function readFile(filename) {
    return new FakePromise(function (resolve) {
        fs.readFile(filename, "utf8", (err, data) => {
            if (err) {
                return
            }
            resolve(data)
        })
    })
}

let content = readFile("config.js")
content.then(res => {
    console.log(res)
})

這樣看來,Promise和發(fā)布-訂閱模式有些相像。promise內(nèi)部也有個事件隊列,通過then注冊事件,通過resolve觸發(fā)。每個promise在創(chuàng)建的時候,就開始執(zhí)行傳遞給它的函數(shù),函數(shù)中會觸發(fā)resolve,這個resolve就是去執(zhí)行所有注冊的事件。

當(dāng)然,實際上promise比這強大的多,首先resolve執(zhí)行所有注冊的事件會保證滯后執(zhí)行,避免還沒通過then注冊完事件,resolve就執(zhí)行了

其次,在異步操作成功之后,通過then注冊事件,可以立馬執(zhí)行,這就需要給promise添加狀態(tài)機制

...
then(onFulfilled) {
        if (this.state === "pending") {
            this.callbacks.push(onFulfilled)
            return this
        }
        onFulfilled(value)
        return this
}
...

判斷不是"pending",就立刻執(zhí)行注冊的函數(shù)

另外就是每個then()方法,都會返回一個新的promise

大概長這樣

then(onFulfilled) {
    return new Promise(...)
}
參考資料

30分鐘,讓你徹底明白Promise原理

生成器
let fs = require("fs")

function run(taskDef){
    // 傳入的taskDef是個生成器函數(shù),執(zhí)行后返回迭代器
    let task = taskDef()
    // 調(diào)用迭代器的next()方法,開始taskDef函數(shù)中的代碼,直至遇到y(tǒng)ield,并將yield的值賦予result
    let result = task.next()
    function step(){
      if(!result.done){
        if(typeof result.value === "function"){
          result.value((err, data)=>{
            if(err){
              result = task.throw(err)
              return
            }
            result = task.next(data)
            step()
          })
          // 這里的result.value(...){...}
          // 調(diào)用的是function(callback){fs.readFile(filename, "utf8", callback)}
        }else{
          result = task.next(data)
          step() // 判斷任務(wù)是否執(zhí)行完
        }
      }
    }
    step()
    // task.next(data) 繼續(xù)執(zhí)行生成器中的代碼,并將值傳回給觸發(fā)這次next()的yield的等號左邊的變量
}

function readFile(filename){
  return function (callback){ // 這里的callback,是在run函數(shù)中傳遞的
    fs.readFile(filename, "utf8", callback)
  }
}

run(function*(){
  let content = yield readFile("config.js") // 傳遞函數(shù)至run函數(shù)中,并由run傳遞參數(shù)調(diào)用
  // 對文件內(nèi)容進(jìn)行處理
  console.log(content)
})
// 對比臆想中的
let content = readFile("config.js")
// 針對讀取到的內(nèi)容進(jìn)行操作,比如打印文件內(nèi)容
console.log(content)

生成器函數(shù)可以停止函數(shù)執(zhí)行,代碼在yield readFile("copy.js")處暫停

異步任務(wù)的回調(diào)中調(diào)用迭代器的next()方法,使生成器函數(shù)中的代碼繼續(xù)執(zhí)行,并通過next()方法傳遞參數(shù)回至生成器函數(shù)中,異步任務(wù)完成,返回值已經(jīng)賦值給了content

Promise+generator
let fs = require("fs")

function run(taskDef){
    // 傳入的taskDef是個生成器函數(shù),執(zhí)行后返回迭代器
    let task = taskDef()
    // 調(diào)用迭代器的next()方法,開始taskDef函數(shù)中的代碼,直至遇到y(tǒng)ield,并將yield的值賦予result
    let result = task.next()
    function step(){
      if(!result.done){
        let promise = Promise.resolve(result.value)
        promise.then(value => {
            result = task.next(value)
            step()
        }).catch(err => {
            result = task.throw(err)
            step()
        })
          
      }
    }
    step()
    // task.next(data) 繼續(xù)執(zhí)行生成器中的代碼,并將值傳回給觸發(fā)這次next()的yield的等號左邊的變量
}

function readFile(filename){
  return new Promise(function (resolve, reject){ // 這里的callback,是在run函數(shù)中傳遞的
    fs.readFile(filename, "utf8", (err, data) => {
        if(err){
            reject(err)
        }
        resolve(data)
    })
  })
}

run(function*(){
  let content = yield readFile("config.js") // 傳遞函數(shù)至run函數(shù)中,并由run傳遞參數(shù)調(diào)用
  // 對文件內(nèi)容進(jìn)行處理
  console.log(content)
})

console.log("先執(zhí)行")
Async&await

是不是和promise+generator很像

let fs = require("fs")

function readFile(filename) {
    return new Promise(function (resolve) { // 這里的callback,是在run函數(shù)中傳遞的
        fs.readFile(filename, "utf8", (err, data) => {
            if (err) {
                reject(err)
            }
            resolve(data)
        })
    })
}
(async function test() {
    let content = await readFile("copy.js")
    console.log(content)
})()
參考資料

深入理解ES6

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/92595.html

相關(guān)文章

  • Java日志正確使用姿勢

    摘要:但是往往越簡單的東西越容易讓我們忽視,從而導(dǎo)致一些不該有的發(fā)生,作為一名嚴(yán)謹(jǐn)?shù)某绦騿T,怎么能讓這種事情發(fā)生呢所以下面我們就來了解一下關(guān)于日志的那些正確使用姿勢。級別表示出現(xiàn)了嚴(yán)重錯誤,程序?qū)袛鄨?zhí)行。 前言 關(guān)于日志,在大家的印象中都是比較簡單的,只須引入了相關(guān)依賴包,剩下的事情就是在項目中盡情的打印我們需要的信息了。但是往往越簡單的東西越容易讓我們忽視,從而導(dǎo)致一些不該有的bug發(fā)...

    UCloud 評論0 收藏0
  • 前端基礎(chǔ)

    摘要:談起閉包,它可是兩個核心技術(shù)之一異步基于打造前端持續(xù)集成開發(fā)環(huán)境本文將以一個標(biāo)準(zhǔn)的項目為例,完全拋棄傳統(tǒng)的前端項目開發(fā)部署方式,基于容器技術(shù)打造一個精簡的前端持續(xù)集成的開發(fā)環(huán)境。 這一次,徹底弄懂 JavaScript 執(zhí)行機制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機制,如果讀完本文還不懂,可以揍我。 不論你是javascript新手還是老鳥,不論是面試求職,還是日...

    graf 評論0 收藏0
  • 論JVM爆炸幾種姿勢及自救方法

    摘要:方法區(qū)溢出在的方法區(qū)中,它主要存放了類的信息,常量,靜態(tài)變量等。運行結(jié)果簡單解決思路一般來說此類問題多出現(xiàn)在存在遞歸的地方,要從代碼里重新審視遞歸未結(jié)束的原因,若遞歸的方法沒問題可以根據(jù)實際情況調(diào)整參數(shù)的大小。 前言 如今不管是在面試還是在我們的工作中,OOM總是不斷的出現(xiàn)在我們的視野中,所以我們有必要去了解一下導(dǎo)致OOM的原因以及一些基本的調(diào)整方法,大家可以通過下面的事例來了解一下什...

    hyuan 評論0 收藏0
  • 聊聊Vue.js組件間通信幾種姿勢

    摘要:子組件向父組件通信方法一使用事件父組件向子組件傳遞事件方法,子組件通過觸發(fā)事件,回調(diào)給父組件。非父子組件兄弟組件之間的數(shù)據(jù)傳遞非父子組件通信,官方推薦使用一個實例作為中央事件總線。 寫在前面 因為對Vue.js很感興趣,而且平時工作的技術(shù)棧也是Vue.js,這幾個月花了些時間研究學(xué)習(xí)了一下Vue.js源碼,并做了總結(jié)與輸出。 文章的原地址:https://github.com/answ...

    Profeel 評論0 收藏0
  • JS常用幾種異步流程控制

    摘要:雖然這個模式運行效果很不錯,但是如果嵌套了太多的回調(diào)函數(shù),就會陷入回調(diào)地獄。當(dāng)需要跟蹤多個回調(diào)函數(shù)的時候,回調(diào)函數(shù)的局限性就體現(xiàn)出來了,非常好的改進(jìn)了這些情況。 JavaScript引擎是基于單線程 (Single-threaded) 事件循環(huán)的概念構(gòu)建的,同一時刻只允許一個代碼塊在執(zhí)行,所以需要跟蹤即將運行的代碼,那些代碼被放在一個任務(wù)隊列 (job queue) 中,每當(dāng)一段代碼準(zhǔn)...

    Barry_Ng 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<