摘要:實(shí)例生成以后,可以用方法分別指定狀態(tài)和狀態(tài)的回調(diào)函數(shù)處理返回的結(jié)果。
文章的目的
揭開go的 gorouter,c#的 async/await等 使用同步的寫法寫異步代碼的神秘面紗 , 證明其本質(zhì)就是一個(gè)語法糖
為什么使用js來講異步編程因?yàn)閖s可以通過編程語言自己的語法特性,實(shí)現(xiàn)async/await語法
js異步最底層寫法promiseconst promise = new Promise(function(resolve, reject) { xxxxx.異步IO操作((res)=>{ if(res成功){ resolve(res) }else{ reject(res) } }) });
promise出入的回調(diào)函數(shù)有一定的要求
resolve函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?pending 變?yōu)?resolved),在異步操作成功時(shí)調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去
reject函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?pending 變?yōu)?rejected),在異步操作失敗時(shí)調(diào)用,并將異步操作報(bào)出的錯誤,作為參數(shù)傳遞出去。
Promise實(shí)例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)(處理返回的結(jié)果)。
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))
這個(gè)的結(jié)果是failt 因?yàn)?p2中resolve返回一個(gè)promise對象,這個(gè)操作將會導(dǎo)致p2的狀態(tài)升級成p1的狀態(tài)(標(biāo)準(zhǔn))promise的then鏈?zhǔn)綄懛?/b>
promise then方法將會返回一個(gè)promise,所以js支持鏈?zhǔn)疆惒?/p>
var getJSON = function (url, callback) { var promise = new Promise(function (resolve, reject) { var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler;//readyState屬性的值由一個(gè)值變?yōu)榱硪粋€(gè)值時(shí),都會觸發(fā)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));
這個(gè)異常捕獲和java相同,捕獲在eventLoop中產(chǎn)生的異常
注意一點(diǎn)這個(gè)異常和java的try catch是不同的,如果產(chǎn)生了異常將不會在主線程中顯示出來promise的finally
這個(gè)和java的異常體系相同,finally 無關(guān)狀態(tài),最后都會執(zhí)行
Promise.resolve(2).finally(() => {})更加方便的編寫異步使用Promise.resolve(xxx)
Promise.resolve("foo") // 等價(jià)于 new Promise(resolve => resolve("foo"))
注意: promise異步化結(jié)果只能在回調(diào)函數(shù)中獲得,如果異步的操作太多,將會調(diào)至調(diào)用鏈路過長如何解決js的promise異步編程的問題?
promise 寫法有什么問題? ---- 調(diào)用鏈路過長
比如: 使用promise 實(shí)現(xiàn) 異步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屬性的值由一個(gè)值變?yōu)榱硪粋€(gè)值時(shí),都會觸發(fā)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); });
調(diào)用鏈太長,不停的promise調(diào)用
js如何解決回調(diào)地獄---同步方法寫異步 解決方法 使用js的協(xié)程 --Generatorgenerator:js的特殊語法,使用yield 關(guān)鍵字將函數(shù)分塊了,然后可以使用遍歷器手動控制執(zhí)行
例子:
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));
本質(zhì)上是函數(shù)分片
js在每次yield的時(shí)候都會獲得當(dāng)前位置的表達(dá)式,然后再手動的嵌入就可以實(shí)現(xiàn)分片控制的效果了
怎么用generator實(shí)現(xiàn)異步化呢 -- yield配合promise實(shí)現(xiàn)異步看一下這個(gè)方法
function* asyncFn(value) { let a = yield promiseOne(value); let b = yield promiseTwo(a); return a + b; }
想讓他能異步執(zhí)行,只要能讓前一個(gè)promise的結(jié)果是下一個(gè)promise的輸入就可以了
這里有兩種寫法
寫法一遞歸方程: f(最終結(jié)果) = f(到目前的結(jié)果)+f(接下來執(zhí)行的結(jié)果)
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);//這個(gè)res方法其實(shí)是所有人的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(最終結(jié)果) = f(之前所有的結(jié)果)+f(最后一步的結(jié)果)
//同步方式寫異步 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
上面復(fù)雜的代碼如果變成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) });
通過上面的例子,我們可以發(fā)現(xiàn)其實(shí)async/await本質(zhì)上其實(shí)是 generator的一個(gè)語法糖
await就是yield , async 的作用就是將函數(shù)編程語法糖
如果背的話很簡答兩條規(guī)則:
await后面必須是promise函數(shù)
async 標(biāo)記過得函數(shù)執(zhí)行后返回的promise
通過這種方法就可以簡單的實(shí)現(xiàn)異步了
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104296.html
摘要:現(xiàn)在在后端業(yè)務(wù)開發(fā)編程方面,技術(shù)力量強(qiáng)的團(tuán)隊(duì)已經(jīng)開始將技術(shù)棧從同步模式切換為異步了。使用這些技術(shù)方案是無法兼容已有程序的。影響了異步回調(diào)技術(shù)棧的普及。將會成為未來后端開發(fā)領(lǐng)域的主流技術(shù)方案。 今天太忙,少寫一點(diǎn),后面再補(bǔ)充。 異步模式 Go 語言越來越熱門,很多大型互聯(lián)網(wǎng)公司后端正在轉(zhuǎn)向 GO 。Java 圈知名的服務(wù)化框架 Dubbo 也宣布轉(zhuǎn)型異步模式。這是一個(gè)大趨勢,異步模式已經(jīng)...
摘要:異步模式編程有四種方法回調(diào)函數(shù)最基本的方法,把寫成的回調(diào)函數(shù)事件監(jiān)聽為綁定事件,當(dāng)發(fā)生某個(gè)事件,就執(zhí)行發(fā)布訂閱,以及本文要介紹的對象。它的思想是,每一個(gè)異步任務(wù)返回一個(gè)對象,該對象有一個(gè)方法,允許指定回調(diào)函數(shù)。 歡迎大家前往騰訊云+社區(qū),獲取更多騰訊海量技術(shù)實(shí)踐干貨哦~ 本文由前端林子發(fā)表于云+社區(qū)專欄 Promise是CommonJS提出的一種規(guī)范,在ES6中已經(jīng)原生支持Promi...
摘要:接下來,我們一起來看看中的異步編程,具體有哪幾種。實(shí)現(xiàn)異步編程的方法一回調(diào)函數(shù)上面不止一次提到了回調(diào)函數(shù)。它是異步編程中,最基本的方法。四對象接下來,我們聊聊與相關(guān)的異步編程方法,對象。 showImg(https://segmentfault.com/img/bVbneWy?w=1600&h=1200); 前言 最近,小伙伴S 問了我一段代碼: const funB = (value...
摘要:前端日報(bào)精選漫談函數(shù)式編程一十年蹤跡的博客前端每周清單的優(yōu)勢與劣勢有望超越在嵌入式及物聯(lián)網(wǎng)的應(yīng)用現(xiàn)狀進(jìn)階系列高階組件詳解一前端之路譯如何充分利用控制臺掘金程序猿升級攻略眾成翻譯中文譯如何充分利用控制臺掘金前端從強(qiáng)制開啟壓縮探 2017-06-27 前端日報(bào) 精選 漫談 JS 函數(shù)式編程(一) - 十年蹤跡的博客前端每周清單: Vue的優(yōu)勢與劣勢;Node.js有望超越Java;JS在嵌...
摘要:什么是是異步編程的一種解決方案,比傳統(tǒng)的解決方案回調(diào)函數(shù)和事件更合理和更強(qiáng)大。函數(shù)可以將狀態(tài)轉(zhuǎn)變?yōu)闋顟B(tài)。對象通過方法來添加回調(diào)函數(shù)。當(dāng)發(fā)生錯誤的時(shí)候可以通過方法,來定義回調(diào)函數(shù)。接受數(shù)組作為參數(shù)傳入,每個(gè)元素都是一個(gè)對象。 大家周末好,要說最近幾年什么語言大紅大紫,當(dāng)屬JavaScript了。話說雖然是10天就創(chuàng)造出的語言,但是人家能文能武。web前端自然不必多說了,各種框架你方登罷我...
閱讀 3328·2023-04-26 00:58
閱讀 1278·2021-09-22 16:04
閱讀 3325·2021-09-02 15:11
閱讀 1576·2019-08-30 15:55
閱讀 2352·2019-08-30 15:55
閱讀 3281·2019-08-23 18:41
閱讀 3473·2019-08-23 18:18
閱讀 2763·2019-08-23 17:53