摘要:實例生成以后,可以用方法分別指定狀態和狀態的回調函數處理返回的結果。
文章的目的
揭開go的 gorouter,c#的 async/await等 使用同步的寫法寫異步代碼的神秘面紗 , 證明其本質就是一個語法糖
為什么使用js來講異步編程因為js可以通過編程語言自己的語法特性,實現async/await語法
js異步最底層寫法promiseconst promise = new Promise(function(resolve, reject) { xxxxx.異步IO操作((res)=>{ if(res成功){ resolve(res) }else{ reject(res) } }) });
promise出入的回調函數有一定的要求
resolve函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從 pending 變為 resolved),在異步操作成功時調用,并將異步操作的結果,作為參數傳遞出去
reject函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。
Promise實例生成以后,可以用then方法分別指定resolved狀態和rejected狀態的回調函數(處理返回的結果)。
promise.then(function(value) { // success }, function(error) { // failure });
引申-注意: promise對象在js中非常特殊,比如下面的例子
const p1 = new Promise(function (resolve, reject) { setTimeout(() => reject(new Error("fail")), 3000) }) const p2 = new Promise(function (resolve, reject) { setTimeout(() => resolve(p1), 1000) }) p2 .then(result => console.log(result)) .catch(error => console.log(error))
這個的結果是failt 因為 p2中resolve返回一個promise對象,這個操作將會導致p2的狀態升級成p1的狀態(標準)promise的then鏈式寫法
promise then方法將會返回一個promise,所以js支持鏈式異步
var getJSON = function (url, callback) { var promise = new Promise(function (resolve, reject) { var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler;//readyState屬性的值由一個值變為另一個值時,都會觸發readystatechange事件 client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); function handler() { if (this.readyState !== 4) { return; } if (this.status === 200) { callback(this.response); resolve(this.response); } else { reject(new Error(this.statusText)) } }; }); return promise; }; getJSON("./e2e-tests/get.json", function (resp) { console.log("get:" + resp.name); }).then(function (json) { getJSON("./e2e-tests/get2.json", function (resp) { console.log("get2:" + resp.name); }) }).catch(function (error) { console.log("error1:" + error); });promise 異常捕獲
p.then((val) => console.log("fulfilled:", val)) .catch((err) => console.log("rejected", err)); // 等同于 p.then((val) => console.log("fulfilled:", val)) .then(null, (err) => console.log("rejected:", err));
這個異常捕獲和java相同,捕獲在eventLoop中產生的異常
注意一點這個異常和java的try catch是不同的,如果產生了異常將不會在主線程中顯示出來promise的finally
這個和java的異常體系相同,finally 無關狀態,最后都會執行
Promise.resolve(2).finally(() => {})更加方便的編寫異步使用Promise.resolve(xxx)
Promise.resolve("foo") // 等價于 new Promise(resolve => resolve("foo"))
注意: promise異步化結果只能在回調函數中獲得,如果異步的操作太多,將會調至調用鏈路過長如何解決js的promise異步編程的問題?
promise 寫法有什么問題? ---- 調用鏈路過長
比如: 使用promise 實現 異步ajax請求
var getJSON = function (url, callback) { var promise = new Promise(function (resolve, reject) { var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler;//readyState屬性的值由一個值變為另一個值時,都會觸發readystatechange事件 client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); function handler() { if (this.readyState !== 4) { return; } if (this.status === 200) { callback(this.response); resolve(this.response); } else { reject(new Error(this.statusText)) } }; }); return promise; }; getJSON("./e2e-tests/get.json", function (resp) { console.log("get:" + resp.name); }).then(function (json) { getJSON("./e2e-tests/get2.json", function (resp) { console.log("get2:" + resp.name); }) }).catch(function (error) { console.log("error1:" + error); });
調用鏈太長,不停的promise調用
js如何解決回調地獄---同步方法寫異步 解決方法 使用js的協程 --Generatorgenerator:js的特殊語法,使用yield 關鍵字將函數分塊了,然后可以使用遍歷器手動控制執行
例子:
function * gen(){ let a= 123; let b = yield a; let c = yield a+b; return a+b+c; } let start = gen(); console.log(start.next()); console.log(start.next(2)); console.log(start.next(3));
本質上是函數分片
js在每次yield的時候都會獲得當前位置的表達式,然后再手動的嵌入就可以實現分片控制的效果了
怎么用generator實現異步化呢 -- yield配合promise實現異步看一下這個方法
function* asyncFn(value) { let a = yield promiseOne(value); let b = yield promiseTwo(a); return a + b; }
想讓他能異步執行,只要能讓前一個promise的結果是下一個promise的輸入就可以了
這里有兩種寫法
寫法一遞歸方程: f(最終結果) = f(到目前的結果)+f(接下來執行的結果)
function promiseOne(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function promiseTwo(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function* asyncFn(value) { let a = yield promiseOne(value); let b = yield promiseTwo(a); return a + b; } function runAsync(fn,value) { let item = fn.next(value); return new Promise((res, rej) => { if (!item.done) { if (item.value instanceof Promise) { item.value.then((re)=>{ runAsync(fn,re).then(res); }) } else { runAsync(fn,fn.valueOf()).then(res); } } else { res(item.value);//這個res方法其實是所有人的res方法 } }) } runAsync(asyncFn(12)).then(res=>{ console.log(res); });
co 工具包的寫法
function run (gen) { gen = gen() return next(gen.next()) function next ({done, value}) { return new Promise(resolve => { if (done) { // finish resolve(value) } else { // not yet value.then(data => { next(gen.next(data)).then(resolve) }) } }) } } function getRandom () { return new Promise(resolve => { setTimeout(_ => resolve(Math.random() * 10 | 0), 1000) }) } function * main () { let num1 = yield getRandom() let num2 = yield getRandom() return num1 + num2 } run(main).then(data => { console.log(`got data: ${data}`); })寫法二
遞歸方程 f(最終結果) = f(之前所有的結果)+f(最后一步的結果)
//同步方式寫異步 function asyncRun(resf, fn, value) { let a = fn(value); go(value); function go(value) { let next = a.next(value); if (!next.done) { if (next.value instanceof Promise) { next.value.then((res) => { go(res); }); } else { return go(next.value); } } else { resf(next.value); } } } function* asyncFn(value) { let a = yield promiseOne(value); let b = yield promiseTwo(a); return a + b; } function show(item) { console.log(item) } asyncRun(show, asyncFn, 12); function promiseOne(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function promiseTwo(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) }更簡單的方法 async/await
上面復雜的代碼如果變成async/await要怎么做呢
很簡單
// function* asyncFn(value) { // let a = yield promiseOne(value); // let b = yield promiseTwo(a); // return a + b; // } function promiseOne(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } function promiseTwo(xxx) { return new Promise((res, rej) => { res(xxx + 1); }) } async function asyncFn(value) { let a = await promiseOne(value); let b = await promiseTwo(a); return a + b; } asyncFn(12).then((res)=>{ console.log(res) });
通過上面的例子,我們可以發現其實async/await本質上其實是 generator的一個語法糖
await就是yield , async 的作用就是將函數編程語法糖
如果背的話很簡答兩條規則:
await后面必須是promise函數
async 標記過得函數執行后返回的promise
通過這種方法就可以簡單的實現異步了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104296.html
摘要:現在在后端業務開發編程方面,技術力量強的團隊已經開始將技術棧從同步模式切換為異步了。使用這些技術方案是無法兼容已有程序的。影響了異步回調技術棧的普及。將會成為未來后端開發領域的主流技術方案。 今天太忙,少寫一點,后面再補充。 異步模式 Go 語言越來越熱門,很多大型互聯網公司后端正在轉向 GO 。Java 圈知名的服務化框架 Dubbo 也宣布轉型異步模式。這是一個大趨勢,異步模式已經...
摘要:異步模式編程有四種方法回調函數最基本的方法,把寫成的回調函數事件監聽為綁定事件,當發生某個事件,就執行發布訂閱,以及本文要介紹的對象。它的思想是,每一個異步任務返回一個對象,該對象有一個方法,允許指定回調函數。 歡迎大家前往騰訊云+社區,獲取更多騰訊海量技術實踐干貨哦~ 本文由前端林子發表于云+社區專欄 Promise是CommonJS提出的一種規范,在ES6中已經原生支持Promi...
摘要:接下來,我們一起來看看中的異步編程,具體有哪幾種。實現異步編程的方法一回調函數上面不止一次提到了回調函數。它是異步編程中,最基本的方法。四對象接下來,我們聊聊與相關的異步編程方法,對象。 showImg(https://segmentfault.com/img/bVbneWy?w=1600&h=1200); 前言 最近,小伙伴S 問了我一段代碼: const funB = (value...
摘要:前端日報精選漫談函數式編程一十年蹤跡的博客前端每周清單的優勢與劣勢有望超越在嵌入式及物聯網的應用現狀進階系列高階組件詳解一前端之路譯如何充分利用控制臺掘金程序猿升級攻略眾成翻譯中文譯如何充分利用控制臺掘金前端從強制開啟壓縮探 2017-06-27 前端日報 精選 漫談 JS 函數式編程(一) - 十年蹤跡的博客前端每周清單: Vue的優勢與劣勢;Node.js有望超越Java;JS在嵌...
摘要:什么是是異步編程的一種解決方案,比傳統的解決方案回調函數和事件更合理和更強大。函數可以將狀態轉變為狀態。對象通過方法來添加回調函數。當發生錯誤的時候可以通過方法,來定義回調函數。接受數組作為參數傳入,每個元素都是一個對象。 大家周末好,要說最近幾年什么語言大紅大紫,當屬JavaScript了。話說雖然是10天就創造出的語言,但是人家能文能武。web前端自然不必多說了,各種框架你方登罷我...
閱讀 3313·2023-04-26 00:58
閱讀 1268·2021-09-22 16:04
閱讀 3311·2021-09-02 15:11
閱讀 1554·2019-08-30 15:55
閱讀 2339·2019-08-30 15:55
閱讀 3247·2019-08-23 18:41
閱讀 3458·2019-08-23 18:18
閱讀 2752·2019-08-23 17:53