摘要:完成請問應該如何安排操作流程上面代碼采用個回調(diào)函數(shù)的嵌套,不僅寫起來麻煩,容易出錯,而且難以維護串行執(zhí)行我們可以編寫一個流程控制函數(shù),讓它來控制異步任務,一個任務完成以后,再執(zhí)行另一個。
前言
回調(diào)地獄
Javascript 語言的執(zhí)行環(huán)境是“單線程”(single thread)。所謂“單線程”,就是指一次只能完成一件任務。如果有多個任務,就必須排隊,前面一個任務完成,再執(zhí)行后面一個任務。
這種模式的好處是實現(xiàn)起來比較簡單,執(zhí)行環(huán)境相對單純;壞處是只要有一個任務耗時很長,后面的任務都必須排隊等著,會拖延整個程序的執(zhí)行。常見的瀏覽器無響應(假死),往往就是因為某一段 JavaScript 代碼長時間運行(比如死循環(huán)),導致整個頁面卡在這個地方,其他任務無法執(zhí)行。
為了解決這個問題,Javascript 語言將任務的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)。
回調(diào)函數(shù)假定有兩個函數(shù)f1和f2,后者必須等到前者執(zhí)行完成,才能執(zhí)行。這時,可以考慮改寫f1,把f2寫成f1的回調(diào)函數(shù)。
function f1(callback) { callback(); }事件監(jiān)聽
f1.on("done", f2); function f1(){ setTimeout(function () { // f1的任務代碼 f1.trigger("done"); }, 1000); }發(fā)布訂閱
jQuery.subscribe("done", f2); function f1(){ setTimeout(function () { // f1的任務代碼 jQuery.publish("done"); }, 1000); } jQuery.unsubscribe("done", f2);
這種方法的性質(zhì)與”事件監(jiān)聽”類似,但是明顯優(yōu)于后者。因為我們可以通過查看”消息中心”,了解存在多少信號、每個信號有多少訂閱者,從而監(jiān)控程序的運行。
js異步操作流程控制如果有多個異步操作,就存在一個流程控制的問題:確定操作執(zhí)行的順序,以后如何保證遵守這種順序
function async(arg, callback) { console.log("參數(shù)為 " + arg +" , 1秒后返回結果"); setTimeout(function() { callback(arg * 2); }, 1000); }
上面代碼的async函數(shù)是一個異步任務,非常耗時,每次執(zhí)行需要1秒才能完成,然后再調(diào)用回調(diào)函數(shù)。
如果有6個這樣的異步任務,需要全部完成后,才能執(zhí)行下一步的final函數(shù)。
function final(value) { console.log("完成: ", value); }
請問應該如何安排操作流程?
async(1, function(value){ async(value, function(value){ async(value, function(value){ async(value, function(value){ async(value, function(value){ async(value, final); }); }); }); }); });
上面代碼采用6個回調(diào)函數(shù)的嵌套,不僅寫起來麻煩,容易出錯,而且難以維護
串行執(zhí)行我們可以編寫一個流程控制函數(shù),讓它來控制異步任務,一個任務完成以后,再執(zhí)行另一個。這就叫串行執(zhí)行。(任務隊列)
let taskQueen = [1, 2, 3, 4, 5, 6]; let result = []; function invoke(curTask) { if (curTask) { console.log("當前正在執(zhí)行任務", curTask); result.push(curTask + "完成"); } else { console.log("當前任務全部完成"); } } invoke(taskQueen.shift());
var items = [ 1, 2, 3, 4, 5, 6 ]; var results = []; function series(item) { if(item) { async( item, function(result) { results.push(result); return series(items.shift()); }); } else { return final(results); } } series(items.shift());并行
var items = [ 1, 2, 3, 4, 5, 6 ]; var results = []; items.forEach(function(item) { async(item, function(result){ results.push(result); if(results.length == items.length) { final(results); } }) });
上面代碼中,forEach方法會同時發(fā)起6個異步任務,等到它們?nèi)客瓿梢院螅艜?zhí)行final函數(shù)。
并行執(zhí)行的好處是效率較高,比起串行執(zhí)行一次只能執(zhí)行一個任務,較為節(jié)約時間。但是問題在于如果并行的任務較多,很容易耗盡系統(tǒng)資源,拖慢運行速度。因此有了第三種流程控制方式
function launcher() { while(running < limit && items.length > 0) { var item = items.shift(); async(item, function(result) { results.push(result); running--; if(items.length > 0) { launcher(); } else if(running == 0) { final(results); } }); running++; } } launcher();promise
Promise 對象用于一個異步操作的最終完成(或失敗)及其結果值的表示。(簡單點說就是處理異步請求。我們經(jīng)常會做些承諾,如果我贏了你就嫁給我,如果輸了我就嫁給你之類的諾言。這就是promise的中文含義:諾言,一個成功,一個失敗。) -MDN
new Promise( /* executor */ function(resolve, reject) {...} );
一個 Promise有以下幾種狀態(tài):
pending: 初始狀態(tài),不是成功或失敗狀態(tài)。
fulfilled: 意味著操作成功完成。
rejected: 意味著操作失敗。
then()var promise = new Promise(function(resolve, reject){ resolve("傳遞給then的值"); }); promise.then(function (value) { console.log(value); }, function (error) { console.error(error); });catch()
捕獲promise 運行的各種錯誤 promise.then(undefined, onRejected)
的語法糖
var promise = new Promise(function(resolve, reject){ resolve("傳遞給then的值"); }); promise.then(function (value) { console.log(value); }).catch(function (error) { console.error(error); });Promise.resolve && Promise.reject Promise.all
生成并返回一個新的promise對象。
參數(shù)傳遞promise數(shù)組中所有的promise對象都變?yōu)閞esolve的時候,該方法才會返回, 新創(chuàng)建的promise則會使用這些promise的值。
如果參數(shù)中的任何一個promise為reject的話,則整個Promise.all調(diào)用會立即終止,并返回一個reject的新的promise對象。
由于參數(shù)數(shù)組中的每個元素都是由 Promise.resolve 包裝(wrap)的,所以Paomise.all可以處理不同類型的promose對象。
var p1 = Promise.resolve(1), p2 = Promise.resolve(2), p3 = Promise.resolve(3); Promise.all([p1, p2, p3]).then(function (results) { console.log(results); // [1, 2, 3] });Promise.race
var p1 = Promise.resolve(1), p2 = Promise.resolve(2), p3 = Promise.resolve(3); Promise.race([p1, p2, p3]).then(function (value) { console.log(value); // 1 });
生成并返回一個新的promise對象。
參數(shù) promise 數(shù)組中的任何一個promise對象如果變?yōu)閞esolve或者reject的話, 該函數(shù)就會返回,并使用這個promise對象的值進行resolve或者reject。
參考JavaScript Promise迷你書(中文版)
promise阮一峰(http://javascript.ruanyifeng....
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/89043.html
摘要:需求背景系統(tǒng)有數(shù)據(jù)識別數(shù)據(jù)脫敏邏輯,支持可配置規(guī)則,自定義等,需要進行異構數(shù)據(jù)同步,大數(shù)據(jù)量。可用性分析可用性表格分析場景影響降級原因某臺數(shù)據(jù)同步下線無影響數(shù)據(jù)同步無狀態(tài),調(diào)度平臺重連其他的數(shù)據(jù)同步服務。 需求背景 系統(tǒng)有數(shù)據(jù)識別、數(shù)據(jù)脫敏邏輯,支持可配置規(guī)則,自定義等,需要進行異構數(shù)據(jù)同步,大數(shù)據(jù)量。現(xiàn)在針對以下幾個需求進行講解 1、支持冗余設計2、支持任務自動分發(fā),支持自動負載均衡...
摘要:第篇簡單異構系統(tǒng)之微服務一大致介紹因為在后面要利用集成異構系統(tǒng),所以才有了本章節(jié)的微服務本章節(jié)使用了最簡單的請求截取的方式,截取不同的后綴做不同的響應處理,簡直二實現(xiàn)步驟添加服務端文件引入模塊創(chuàng)建獲得請求的路徑訪問,將會返回歡迎 SpringCloud(第 026 篇)簡單異構系統(tǒng)之 nodejs 微服務 - 一、大致介紹 1、因為在后面要利用 SpringCloud 集成異構系統(tǒng),所...
摘要:只要指定過這些事件的回調(diào)函數(shù),這些事件發(fā)生時就會進入任務隊列,等待主線程讀取。異步任務必須指定回調(diào)函數(shù),當主線程開始執(zhí)行異步任務,就是執(zhí)行對應的回調(diào)函數(shù)。 javascript語言是一門單線程的語言,不像java語言,類繼承Thread再來個thread.start就可以開辟一個線程。所以,javascript就像一條流水線,僅僅是一條流水線而已,要么加工,要么包裝,不能同時進行多個任...
摘要:這兩個操作符都是編譯器默認引入了類,最后都調(diào)用方法返回對象,臨時對象被回收,因此效率極為低下 Java String類筆記 聲明 文章均為本人技術筆記,轉(zhuǎn)載請注明出處https://segmentfault.com/u/yzwall String的不可變性 String的不可變性 // String declaration public final class String ...
摘要:出場人物老張,水壺兩把普通水壺,簡稱水壺會響的水壺,簡稱響水壺。同步非阻塞老張還是覺得自己有點傻,于是變高端了,買了把會響笛的那種水壺。所謂阻塞非阻塞,僅僅對于老張而言。 1、例子 老張愛喝茶,廢話不說,煮開水。出場人物:老張,水壺兩把(普通 水壺,簡稱水壺;會響的水壺,簡稱響水壺)。 1 老張把水壺放到火上,立等水開。(同步阻塞) 老張覺得自己有點傻 2 老張把...
閱讀 3968·2021-11-16 11:44
閱讀 5189·2021-10-09 09:54
閱讀 2031·2019-08-30 15:44
閱讀 1678·2019-08-29 17:22
閱讀 2753·2019-08-29 14:11
閱讀 3389·2019-08-26 13:25
閱讀 2324·2019-08-26 11:55
閱讀 1595·2019-08-26 10:37