摘要:臆想的針對讀取到的內容進行操作,比如打印文件內容臆想中,讀取文件是有返回值的,將返回值,即文件內容,賦給一個變量,然后決定對讀取到的內容進行相應的操作,例如打印文件中的內容。
臆想的
let fs = require("fs") function readFile(filename){ ... } let content = readFile("config.js") // 針對讀取到的內容進行操作,比如打印文件內容 console.log(content)
臆想中,讀取文件是有返回值的,將返回值,即文件內容,賦給一個變量,然后決定對讀取到的內容進行相應的操作,例如打印文件中的內容。
簡而言之,臆想中,讀取文件,打印文件是相互分開的。
回調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) })
實際上,在經常使用的回調中,讀取文件和針對文件內容相應的操作是在一起的,
你在要求讀取文件的同時,還要說明獲取文件內容后干嘛
這和習慣性思維,你先把文件內容給我,至于我怎么處理,稍后再說
Promiselet fs = require("fs") function readFile(filename) { return new Promise(function (resolve) { // 這里的callback,是在run函數中傳遞的 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") // 針對讀取到的內容進行操作,比如打印文件內容 console.log(content)
使用Promise后,整個書寫邏輯開始和臆想中的很接近了,讀取文件和對文件內容的操作分開了
即通過使用Promise,可以將異步的操作和對異步結果的處理,分開
來實現一個簡陋的假的Promiselet fs = require("fs") function resolve(value) { let _self = this setTimeout(function () { _self.callbacks.forEach(function (callback) { callback(value); }) }, 0) // 保證在resolve執行之前,then方法都已經注冊 } class FakePromise { constructor(fn) { // fn是個函數,里面包含異步,異步成功 // Promise在new的過程中就已經開始執行異步代碼 // 異步代碼執行完觸發resolve,resolve作為異步代碼的參數,它早已經實現好 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和發布-訂閱模式有些相像。promise內部也有個事件隊列,通過then注冊事件,通過resolve觸發。每個promise在創建的時候,就開始執行傳遞給它的函數,函數中會觸發resolve,這個resolve就是去執行所有注冊的事件。
當然,實際上promise比這強大的多,首先resolve執行所有注冊的事件會保證滯后執行,避免還沒通過then注冊完事件,resolve就執行了
其次,在異步操作成功之后,通過then注冊事件,可以立馬執行,這就需要給promise添加狀態機制
... then(onFulfilled) { if (this.state === "pending") { this.callbacks.push(onFulfilled) return this } onFulfilled(value) return this } ...
判斷不是"pending",就立刻執行注冊的函數
另外就是每個then()方法,都會返回一個新的promise
大概長這樣
then(onFulfilled) { return new Promise(...) }參考資料
30分鐘,讓你徹底明白Promise原理
生成器let fs = require("fs") function run(taskDef){ // 傳入的taskDef是個生成器函數,執行后返回迭代器 let task = taskDef() // 調用迭代器的next()方法,開始taskDef函數中的代碼,直至遇到yield,并將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(...){...} // 調用的是function(callback){fs.readFile(filename, "utf8", callback)} }else{ result = task.next(data) step() // 判斷任務是否執行完 } } } step() // task.next(data) 繼續執行生成器中的代碼,并將值傳回給觸發這次next()的yield的等號左邊的變量 } function readFile(filename){ return function (callback){ // 這里的callback,是在run函數中傳遞的 fs.readFile(filename, "utf8", callback) } } run(function*(){ let content = yield readFile("config.js") // 傳遞函數至run函數中,并由run傳遞參數調用 // 對文件內容進行處理 console.log(content) }) // 對比臆想中的 let content = readFile("config.js") // 針對讀取到的內容進行操作,比如打印文件內容 console.log(content)
生成器函數可以停止函數執行,代碼在yield readFile("copy.js")處暫停
異步任務的回調中調用迭代器的next()方法,使生成器函數中的代碼繼續執行,并通過next()方法傳遞參數回至生成器函數中,異步任務完成,返回值已經賦值給了content
Promise+generatorlet fs = require("fs") function run(taskDef){ // 傳入的taskDef是個生成器函數,執行后返回迭代器 let task = taskDef() // 調用迭代器的next()方法,開始taskDef函數中的代碼,直至遇到yield,并將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) 繼續執行生成器中的代碼,并將值傳回給觸發這次next()的yield的等號左邊的變量 } function readFile(filename){ return new Promise(function (resolve, reject){ // 這里的callback,是在run函數中傳遞的 fs.readFile(filename, "utf8", (err, data) => { if(err){ reject(err) } resolve(data) }) }) } run(function*(){ let content = yield readFile("config.js") // 傳遞函數至run函數中,并由run傳遞參數調用 // 對文件內容進行處理 console.log(content) }) console.log("先執行")Async&await
是不是和promise+generator很像
let fs = require("fs") function readFile(filename) { return new Promise(function (resolve) { // 這里的callback,是在run函數中傳遞的 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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92595.html
摘要:但是往往越簡單的東西越容易讓我們忽視,從而導致一些不該有的發生,作為一名嚴謹的程序員,怎么能讓這種事情發生呢所以下面我們就來了解一下關于日志的那些正確使用姿勢。級別表示出現了嚴重錯誤,程序將會中斷執行。 前言 關于日志,在大家的印象中都是比較簡單的,只須引入了相關依賴包,剩下的事情就是在項目中盡情的打印我們需要的信息了。但是往往越簡單的東西越容易讓我們忽視,從而導致一些不該有的bug發...
摘要:方法區溢出在的方法區中,它主要存放了類的信息,常量,靜態變量等。運行結果簡單解決思路一般來說此類問題多出現在存在遞歸的地方,要從代碼里重新審視遞歸未結束的原因,若遞歸的方法沒問題可以根據實際情況調整參數的大小。 前言 如今不管是在面試還是在我們的工作中,OOM總是不斷的出現在我們的視野中,所以我們有必要去了解一下導致OOM的原因以及一些基本的調整方法,大家可以通過下面的事例來了解一下什...
摘要:子組件向父組件通信方法一使用事件父組件向子組件傳遞事件方法,子組件通過觸發事件,回調給父組件。非父子組件兄弟組件之間的數據傳遞非父子組件通信,官方推薦使用一個實例作為中央事件總線。 寫在前面 因為對Vue.js很感興趣,而且平時工作的技術棧也是Vue.js,這幾個月花了些時間研究學習了一下Vue.js源碼,并做了總結與輸出。 文章的原地址:https://github.com/answ...
摘要:雖然這個模式運行效果很不錯,但是如果嵌套了太多的回調函數,就會陷入回調地獄。當需要跟蹤多個回調函數的時候,回調函數的局限性就體現出來了,非常好的改進了這些情況。 JavaScript引擎是基于單線程 (Single-threaded) 事件循環的概念構建的,同一時刻只允許一個代碼塊在執行,所以需要跟蹤即將運行的代碼,那些代碼被放在一個任務隊列 (job queue) 中,每當一段代碼準...
閱讀 5075·2023-04-25 19:30
閱讀 2172·2023-04-25 15:09
閱讀 2617·2021-11-16 11:45
閱讀 2170·2021-11-15 18:07
閱讀 1457·2021-11-11 17:22
閱讀 2114·2021-11-04 16:06
閱讀 3576·2021-10-20 13:47
閱讀 3035·2021-09-22 16:03