摘要:回調的問題異常處理異步代碼時不再生效捕獲錯誤因為這個回調函數被存放了起來,直到下一個事件環的時候才會取出只能捕獲當前循環內的異常,對異步無能為力。
異步
所謂"異步",簡單說就是一個任務分成兩段,先執行第一段,然后轉而執行其他任務,等做好了準備,再回過頭執行第二段,比如,有一個任務是讀取文件進行處理,異步的執行過程就是下面這樣。高階函數這種不連續的執行,就叫做異步。相應地,連續的執行,就叫做同步。
函數作為一等公民,可以作為參數和返回值可以用于批量生成函數
let toString = Object.prototype.toString; let isString = function (obj) { return toString.call(obj) == `[object String]`; } let isFunction = function (obj) { return toString.call(obj) == `[object Function]`; } let isType = function (type) { return function (obj) { return toString.call(obj) == `[object ${type}]`; } }可以用于需要調用多次才執行的函數
let after = function(times,task){ return function(){ if(times--==1){ return task.apply(this,arguments); } } } let fn = after(3,function(){ console.log(3);}); fn();異步編程的語法目標,就是怎樣讓它更像同步編程,有以下幾種
回調函數實現
事件監聽
發布訂閱
Promise/A+ 和生成器函數
async/await
回調所謂回調函數,就是把任務的第二段多帶帶寫在一個函數里面,等到重新執行這個任務的時候,就直接調用這個函數
fs.readFile("某個文件", function (err, data) { if (err) throw err; console.log(data); });
這是一個錯誤優先的回調函數(error-first callbacks),這也是Node.js本身的特點之一。
回調的問題 異常處理try{ //xxx }catch(e){//TODO} 異步代碼時try catch不再生效 let async = function(callback){ try{ setTimeout(function(){ callback(); },1000) }catch(e){ console.log("捕獲錯誤",e); } } async(function(){ console.log(t); });
因為這個回調函數被存放了起來,直到下一個事件環的時候才會取出,try只能捕獲當前循環內的異常,對callback異步無能為力。
Node在處理異常有一個約定,將異常作為回調的第一個實參傳回,如果為空表示沒有出錯。
async(function(err,callback){ if(err){ console.log(err); } });
異步方法也要遵循兩個原則
必須在異步之后調用傳入的回調函數
如果出錯了要向回調函數傳入異常供調用者判斷
let async = function(callback){ try{ setTimeout(function(){ if(success) callback(null); else callback("錯誤"); },1000) }catch(e){ console.log("捕獲錯誤",e); } }回調地獄
異步多級依賴的情況下嵌套非常深,代碼難以閱讀的維護
let fs = require("fs"); fs.readFile("template.txt","utf8",function(err,template){ fs.readFile("data.txt","utf8",function(err,data){ console.log(template+" "+data); }) })異步流程解決方案 事件發布/訂閱模型
訂閱事件實現了一個事件與多個回調函數的關聯
let fs = require("fs"); let EventEmitter = require("events"); let eve = new EventEmitter(); let html = {}; eve.on("ready",function(key,value){ html[key] = value; if(Object.keys(html).length==2){ console.log(html); } }); function render(){ fs.readFile("template.txt","utf8",function(err,template){ eve.emit("ready","template",template); }) fs.readFile("data.txt","utf8",function(err,data){ eve.emit("ready","data",data); }) } render();哨兵變量
let fs = require("fs"); let after = function(times,callback){ let result = {}; return function(key,value){ result[key] = value; if(Object.keys(result).length==times){ callback(result); } } } let done = after(2,function(result){ console.log(result); }); function render(){ fs.readFile("template.txt","utf8",function(err,template){ done("template",template); }) fs.readFile("data.txt","utf8",function(err,data){ done("data",data); }) } rendePromise/Deferred模式 生成器Generators/ yield
當你在執行一個函數的時候,你可以在某個點暫停函數的執行,并且做一些其他工作,然后再返回這個函數繼續執行, 甚至是攜帶一些新的值,然后繼續執行。
上面描述的場景正是JavaScript生成器函數所致力于解決的問題。當我們調用一個生成器函數的時候,它并不會立即執行, 而是需要我們手動的去執行迭代操作(next方法)。也就是說,你調用生成器函數,它會返回給你一個迭代器。迭代器會遍歷每個中斷點。
next方法返回值的value屬性,是Generator函數向外輸出數據next方法還可以接受參數,這是向 Generator 函數體內輸入數據
function* foo () { var index = 0; while (index < 2) { yield index++; //暫停函數執行,并執行yield后的操作 } } var bar = foo(); // 返回的其實是一個迭代器 console.log(bar.next()); // { value: 0, done: false } console.log(bar.next()); // { value: 1, done: false } console.log(bar.next()); // { value: undefined, done: true }
Coco是一個為Node.js和瀏覽器打造的基于生成器的流程控制工具,借助于Promise,你可以使用更加優雅的方式編寫非阻塞代碼。
let fs = require("fs"); function readFile(filename) { return new Promise(function (resolve, reject) { fs.readFile(filename, function (err, data) { if (err) reject(err); else resolve(data); }) }) } function *read() { let template = yield readFile("./template.txt"); let data = yield readFile("./data.txt"); return template + "+" + data; } co(read).then(function (data) { console.log(data); }, function (err) { console.log(err); }); function co(gen) { let it = gen(); return new Promise(function (resolve, reject) { !function next(lastVal) { let {value, done} = it.next(lastVal); if (done) { resolve(value); } else { value.then(next, reason => reject(reason)); } }(); }); }Async/ await
使用async關鍵字,你可以輕松地達成之前使用生成器和co函數所做到的工作Async的優點
內置執行器
更好的語義
更廣的適用性
let fs = require("fs"); function readFile(filename) { return new Promise(function (resolve, reject) { fs.readFile(filename, "utf8", function (err, data) { if (err) reject(err); else resolve(data); }) }) } async function read() { let template = await readFile("./template.txt"); let data = await readFile("./data.txt"); return template + "+" + data; } let result = read(); result.then(data=>console.log(data));
async 函數的實現
async 函數的實現,就是將 Generator 函數和自動執行器,包裝在一個函數里。
async function read() { let template = await readFile("./template.txt"); let data = await readFile("./data.txt"); return template + "+" + data; }
// 等同于 function read(){ return co(function*() { let template = yield readFile("./template.txt"); let data = yield readFile("./data.txt"); return template + "+" + data; }); } async_function- generator
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101790.html
摘要:異步時序問題吾輩的博客原文場景死后我們必升天堂,因為活時我們已在地獄。關鍵點異步操作得到結果的時間順序是不確定的如果觸發事件的頻率較高異步操作的時間過長出現這種問題怎么解決既然關鍵點由兩個要素組成,那么,只要破壞了任意一個即可。 JavaScript 異步時序問題 吾輩的博客原文:https://blog.rxliuli.com/p/de... 場景 死后我們必升天堂,因為活時我們已...
摘要:同步與異步以上為同步代碼,函數必須等函數執行完畢后才能執行。異步回調產生的結果就是,函數的調用并不直接返回結果,而往往是交給回調函數進行異步處理。 同步與異步: function a(){} function b(){} a(); b(); 以上為同步代碼,函數b必須等函數a執行完畢后才能執行。 function a(){ ...
摘要:同步和異步先說個傻子的故事有個傻子,第一次用某雷下載大片,就是大人看的片,咳咳咳。。。 1.同步和異步 1.1先說個傻子的故事 有個傻子,第一次用某雷下載大片,就是大人看的片,咳咳咳。。。 某雷告訴他,下載時間要倆小時,傻子心想,要倆小時吶,我第一次用某雷,我得盯著它下載,啥也不能干 于是傻子就干瞪著電腦,等著片下完,這倆小時,傻子啥也沒干 后來,傻子變聰明了,他想,反正某雷在幫他下...
摘要:事件循環事件循環是指主線程重復從消息隊列中取消息執行的過程。事件觸發時,表示異步任務完成,會將事件監聽器函數封裝成一條消息放到消息隊列中,等待主線程執行。 一. 單線程 我們常說JavaScript是單線程的。 所謂單線程,是指在JS引擎中負責解釋和執行JavaScript代碼的線程只有一個。不妨叫它主線程。 但是實際上還存在其他的線程。例如:處理AJAX請求的線程、處理DOM事件的線...
摘要:例如處理請求的線程處理事件的線程定時器線程讀寫文件的線程例如在中等等。事件循環事件循環是指主線程重復從消息隊列中取消息執行的過程。事件觸發時,表示異步任務完成,會將事件監聽器函數封裝成一條消息放到消息隊列中,等待主線程執行。 一. 單線程 我們常說JavaScript是單線程的。 所謂單線程,是指在JS引擎中負責解釋和執行JavaScript代碼的線程只有一個。不妨叫它主線程。 但是實...
閱讀 3344·2021-11-10 11:36
閱讀 3244·2021-10-08 10:21
閱讀 2841·2021-09-29 09:35
閱讀 2416·2021-09-22 16:06
閱讀 3959·2021-09-09 09:33
閱讀 1327·2019-08-30 15:44
閱讀 3171·2019-08-30 10:59
閱讀 2982·2019-08-29 15:32