成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

小程序·云開發(fā)的云函數(shù)路由高級(jí)玩法

ASCH / 3496人閱讀

摘要:甚至如果你的小程序的后臺(tái)邏輯不復(fù)雜,請(qǐng)求量不是特別大,完全可以在云函數(shù)里面做一個(gè)單一的微服務(wù),根據(jù)路由來處理任務(wù)。介紹及用法為了方便大家試用,咱們騰訊云團(tuán)隊(duì)開發(fā)了,云函數(shù)路由管理庫方便大家使用。

李成熙,騰訊云高級(jí)工程師。2014年度畢業(yè)加入騰訊AlloyTeam,先后負(fù)責(zé)過QQ群、花樣直播、騰訊文檔等項(xiàng)目。2018年加入騰訊云云開發(fā)團(tuán)隊(duì)。專注于性能優(yōu)化、工程化和小程序服務(wù)。微博 | 知乎 | Github
概念回顧

在掘金開發(fā)者大會(huì)上,在推薦實(shí)踐那里,我有提到一種云函數(shù)的用法,我們可以將相同的一些操作,比如用戶管理、支付邏輯,按照業(yè)務(wù)的相似性,歸類到一個(gè)云函數(shù)里,這樣比較方便管理、排查問題以及邏輯的共享。甚至如果你的小程序的后臺(tái)邏輯不復(fù)雜,請(qǐng)求量不是特別大,完全可以在云函數(shù)里面做一個(gè)單一的微服務(wù),根據(jù)路由來處理任務(wù)。

用下面三幅圖可以概括,我們來回顧一下:

比如這里就是傳統(tǒng)的云函數(shù)用法,一個(gè)云函數(shù)處理一個(gè)任務(wù),高度解耦。

第二幅架構(gòu)圖就是嘗試將請(qǐng)求歸類,一個(gè)云函數(shù)處理某一類的請(qǐng)求,比如有專門負(fù)責(zé)處理用戶的,或者專門處理支付的云函數(shù)。

最后一幅圖顯示這里只有一個(gè)云函數(shù),云函數(shù)里有一個(gè)分派任務(wù)的路由管理,將不同的任務(wù)分配給不同的本地函數(shù)處理。

tcb-router 介紹及用法

為了方便大家試用,咱們騰訊云 Tencent Cloud Base 團(tuán)隊(duì)開發(fā)了 tcb-router,云函數(shù)路由管理庫方便大家使用。

那具體怎么使用 tcb-router 去實(shí)現(xiàn)上面提到的架構(gòu)呢?下面我會(huì)逐一舉例子。

架構(gòu)一:一個(gè)云函數(shù)處理一個(gè)任務(wù)
這種架構(gòu)下,其實(shí)不需要用到 tcb-router,像普通那樣寫好云函數(shù),然后在小程序端調(diào)用就可以了。

云函數(shù)

// 函數(shù) router
exports.main = (event, context) => {
    return {
        code: 0,
        message: "success"
    };
};

小程序端

wx.cloud.callFunction({
      name: "router",
      data: {
        name: "tcb",
        company: "Tencent"
      }
    }).then((res) => {
      console.log(res);
    }).catch((e) => {
      console.log(e);
});

架構(gòu)二: 按請(qǐng)求給云函數(shù)歸類
此類架構(gòu)就是將相似的請(qǐng)求歸類到同一個(gè)云函數(shù)處理,比如可以分為用戶管理、支付等等的云函數(shù)。

云函數(shù)

// 函數(shù) user
const TcbRouter = require("tcb-router");

exports.main = async (event, context) => {
    const app = new TcbRouter({ event });
    
    app.router("register", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "register success"
        }
    });

    app.router("login", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "login success"
        }
    });

    return app.serve();
};

// 函數(shù) pay
const TcbRouter = require("tcb-router");

exports.main = async (event, context) => {
    const app = new TcbRouter({ event });
    
    app.router("makeOrder", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "make order success"
        }
    });

    app.router("pay", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "pay success"
        }
    });

    return app.serve();
};

小程序端

// 注冊(cè)用戶
wx.cloud.callFunction({
      name: "user",
      data: {
        $url: "register",
        name: "tcb",
        password: "09876"
      }
    }).then((res) => {
      console.log(res);
    }).catch((e) => {
      console.log(e);
});

// 下單商品
wx.cloud.callFunction({
      name: "pay",
      data: {
        $url: "makeOrder",
        id: "xxxx",
        amount: "3"
      }
    }).then((res) => {
      console.log(res);
    }).catch((e) => {
      console.log(e);
});

架構(gòu)三: 由一個(gè)云函數(shù)處理所有服務(wù)

云函數(shù)

// 函數(shù) router
const TcbRouter = require("tcb-router");

exports.main = async (event, context) => {
    const app = new TcbRouter({ event });
    
    app.router("user/register", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "register success"
        }
    });

    app.router("user/login", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "login success"
        }
    });

    app.router("pay/makeOrder", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "make order success"
        }
    });

    app.router("pay/pay", async (ctx, next) => {
        await next();
    }, async (ctx, next) => {
        await next();
    }, async (ctx) => {
        ctx.body = {
            code: 0,
            message: "pay success"
        }
    });

    return app.serve();
};

小程序端

// 注冊(cè)用戶
wx.cloud.callFunction({
      name: "router",
      data: {
        $url: "user/register",
        name: "tcb",
        password: "09876"
      }
    }).then((res) => {
      console.log(res);
    }).catch((e) => {
      console.log(e);
});

// 下單商品
wx.cloud.callFunction({
      name: "router",
      data: {
        $url: "pay/makeOrder",
        id: "xxxx",
        amount: "3"
      }
    }).then((res) => {
      console.log(res);
    }).catch((e) => {
      console.log(e);
});
借鑒 Koa2 的中間件機(jī)制實(shí)現(xiàn)云函數(shù)的路由管理

小程序·云開發(fā)的云函數(shù)目前更推薦 async/await 的玩法來處理異步操作,因此這里也參考了同樣是基于 async/await 的 Koa2 的中間件實(shí)現(xiàn)機(jī)制。

從上面的一些例子我們可以看出,主要是通過 userouter 兩種方法傳入路由以及相關(guān)處理的中間件。

use 只能傳入一個(gè)中間件,路由也只能是字符串,通常用于 use 一些所有路由都得使用的中間件

// 不寫路由表示該中間件應(yīng)用于所有的路由
app.use(async (ctx, next) => {

});

app.use("router", async (ctx, next) => {

});

router 可以傳一個(gè)或多個(gè)中間件,路由也可以傳入一個(gè)或者多個(gè)。

app.router("router", async (ctx, next) => {

});

app.router(["router", "timer"], async (ctx, next) => {
    await next();
}, async (ctx, next) => {
    await next();
}, async (ctx, next) => {

});

不過,無論是 use 還是 router,都只是將路由和中間件信息,通過 _addMiddleware_addRoute 兩個(gè)方法,錄入到 _routerMiddlewares 該對(duì)象中,用于后續(xù)調(diào)用 serve 的時(shí)候,層層去執(zhí)行中間件。

最重要的運(yùn)行中間件邏輯,則是在 servecompose 兩個(gè)方法里。

serve 里主要的作用是做路由的匹配以及將中間件組合好之后,通過 compose 進(jìn)行下一步的操作。比如以下這段節(jié)選的代碼,其實(shí)是將匹配到的路由的中間件,以及 * 這個(gè)通配路由的中間件合并到一起,最后依次執(zhí)行。

let middlewares = (_routerMiddlewares[url]) ? _routerMiddlewares[url].middlewares : [];
// put * path middlewares on the queue head
if (_routerMiddlewares["*"]) {
    middlewares = [].concat(_routerMiddlewares["*"].middlewares, middlewares);
}

組合好中間件后,執(zhí)行這一段,將中間件 compose 后并返回一個(gè)函數(shù),傳入上下文 this 后,最后將 this.body 的值 resolve,即一般在最后一個(gè)中間件里,通過對(duì) ctx.body 的賦值,實(shí)現(xiàn)云函數(shù)的對(duì)小程序端的返回:

const fn = compose(middlewares);

return new Promise((resolve, reject) => {
    fn(this).then((res) => {
        resolve(this.body);
    }).catch(reject);
});

那么 compose 是怎么組合好這些中間件的呢?這里截取部份代碼進(jìn)行分析

function compose(middleware) {
    /**
     * ... 其它代碼 
     */
    return function (context, next) {
        // 這里的 next,如果是在主流程里,一般 next 都是空。
        let index = -1;

        // 在這里開始處理處理第一個(gè)中間件
        return dispatch(0);

        // dispatch 是核心的方法,通過不斷地調(diào)用 dispatch 來處理所有的中間件
        function dispatch(i) {
            if (i <= index) {
                return Promise.reject(new Error("next() called multiple times"));
            }

            index = i;

            // 獲取中間件函數(shù)
            let handler = middleware[i];

            // 處理完最后一個(gè)中間件,返回 Proimse.resolve
            if (i === middleware.length) {
                handler = next;
            }

            if (!handler) {
                return Promise.resolve();
            }

            try {
                // 在這里不斷地調(diào)用 dispatch, 同時(shí)增加 i 的數(shù)值處理中間件
                return Promise.resolve(handler(context, dispatch.bind(null, i + 1)));
            }
            catch (err) {
                return Promise.reject(err);
            }
        }
    }
}

看完這里的代碼,其實(shí)有點(diǎn)疑惑,怎么通過 Promise.resolve(handler(xxxx)) 這樣的代碼邏輯可以推進(jìn)中間件的調(diào)用呢?

首先,我們知道,handler 其實(shí)就是一個(gè) async function,next,就是 dispatch.bind(null, i + 1) 比如這個(gè):

async (ctx, next) => {
    await next();
}

而我們知道,dispatch 是返回一個(gè) Promise.resolve 或者一個(gè) Promise.reject,因此在 async function 里執(zhí)行 await next(),就相當(dāng)于觸發(fā)下一個(gè)中間件的調(diào)用。

當(dāng) compose 完成后,還是會(huì)返回一個(gè) function (context, next),于是就走到下面這個(gè)邏輯,執(zhí)行 fn 并傳入上下文 this 后,再將在中間件中賦值的 this.body resolve 出來,最終就成為云函數(shù)數(shù)要返回的值。

const fn = compose(middlewares);

return new Promise((resolve, reject) => {
    fn(this).then((res) => {
        resolve(this.body);
    }).catch(reject);
});

看到 Promise.resolve 一個(gè) async function,許多人都會(huì)很困惑。其實(shí)撇除 next 這個(gè)往下調(diào)用中間件的邏輯,我們可以很好地將邏輯簡化成下面這段示例:

let a = async () => {
    console.log(1);
};

let b = async () => {
    console.log(2);

    return 3;
};


let fn = async () => {
    await a();
    return b();
};

Promise.resolve(fn()).then((res) => {
    console.log(res);
});

// 輸出
// 1
// 2
// 3

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108540.html

相關(guān)文章

  • 開發(fā)初探 —— 更簡便的程序開發(fā)模式

    摘要:年加入騰訊云云開發(fā)團(tuán)隊(duì)?;冢品?wù)商發(fā)展出這類更高級(jí)的開發(fā)服務(wù)。小程序云開發(fā)說了這么多無服務(wù)開發(fā)的概念優(yōu)點(diǎn),在小程序無服務(wù)開發(fā)這一塊,騰訊云有什么樣的作品呢。這就是今天要重點(diǎn)介紹的,小程序云開發(fā),這就是騰訊云與微信聯(lián)合研發(fā)后,交出的答卷。 李成熙,騰訊云高級(jí)工程師。2014年度畢業(yè)加入騰訊AlloyTeam,先后負(fù)責(zé)過QQ群、花樣直播、騰訊文檔等項(xiàng)目。2018年加入騰訊云云開發(fā)團(tuán)隊(duì)。...

    iKcamp 評(píng)論0 收藏0
  • 手游開發(fā)如何選擇后端服務(wù)

    摘要:云函數(shù)是萬金油為實(shí)現(xiàn)用戶游戲數(shù)據(jù)存儲(chǔ)和每日任務(wù)分發(fā),我們最先用了存儲(chǔ)服務(wù)和云引擎。不過我們并沒有用提供的來直接調(diào)用存儲(chǔ)服務(wù),而是選擇用調(diào)用云引擎里面的云函數(shù),然后通過云函數(shù)調(diào)用存儲(chǔ)服務(wù)來實(shí)現(xiàn)相應(yīng)的邏輯。 【 玩轉(zhuǎn) LeanCloud 】開發(fā)者投稿分享: 作者:趙天澤 作為一個(gè)通過 LeanCloud 入門后端開發(fā)的小白,一年多的開發(fā)歷程讓我收獲滿滿。多個(gè)項(xiàng)目也在 LeanCloud 可...

    codecook 評(píng)論0 收藏0
  • 計(jì)算的1024種玩法】輕松搭建可自動(dòng)橫向擴(kuò)展的同城雙中心服務(wù)集群

    摘要:同城雙中心服務(wù)災(zāi)備阿里云同地域下不同可用區(qū)的網(wǎng)絡(luò)電力設(shè)備等都是物理隔離的,但是通過內(nèi)網(wǎng)連接。二創(chuàng)建伸縮配置,也就是自動(dòng)添加的云服務(wù)器的配置,這個(gè)過程和購買的流程一致。 前言:云服務(wù)器的特性主要就是體現(xiàn)在橫向、縱向的彈性擴(kuò)容上,縱向的話其實(shí)很好理解就是我們單臺(tái) ECS 配置不夠用了馬上升級(jí)一下配置,不過這種場景比較適合于一個(gè)網(wǎng)站穩(wěn)健的發(fā)展?fàn)顟B(tài),而且波動(dòng)不大?;蛘哒f服務(wù)器有較長時(shí)間的資源占...

    ChristmasBoy 評(píng)論0 收藏0
  • 計(jì)算的1024種玩法】輕松搭建可自動(dòng)橫向擴(kuò)展的同城雙中心服務(wù)集群

    摘要:同城雙中心服務(wù)災(zāi)備阿里云同地域下不同可用區(qū)的網(wǎng)絡(luò)電力設(shè)備等都是物理隔離的,但是通過內(nèi)網(wǎng)連接。二創(chuàng)建伸縮配置,也就是自動(dòng)添加的云服務(wù)器的配置,這個(gè)過程和購買的流程一致。 前言:云服務(wù)器的特性主要就是體現(xiàn)在橫向、縱向的彈性擴(kuò)容上,縱向的話其實(shí)很好理解就是我們單臺(tái) ECS 配置不夠用了馬上升級(jí)一下配置,不過這種場景比較適合于一個(gè)網(wǎng)站穩(wěn)健的發(fā)展?fàn)顟B(tài),而且波動(dòng)不大?;蛘哒f服務(wù)器有較長時(shí)間的資源占...

    testHs 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<