أداء SSR إضافي مع خادم Nuxt fullstack (الجزء 2)

أداء SSR إضافي مع خادم Nuxt fullstack


في الجزء 1 ، وصفت مدى سهولة تنظيم خادم API في Nuxt . في الجزء الثاني ، أريد أن أخبرك بالمزايا الإضافية التي يمكنك الحصول عليها من خادم Nuxt fullstack .

الجزء 2: تسريع عرض الخادم!


دعونا نفكر الآن في كيفية عمل الخادم الخاص بنا من مثال codeandbox.io/s/codesandbox-nuxt-3gzhl

  1. يطلب العميل الصفحة الرئيسية 3gzhl.sse.codesandbox.io
  2. يبدأ Nuxt في عرض الصفحة /pages/index.vue على الخادم
  3. تاتي الى

      async fetch() {
        this.users = await this.$api("users", "index");
      },
    
  4. عبر أكسيوس، وقال انه يجعل طلب HTTP ، في 3gzhl.sse.codesandbox.io/api/users/index أي على نفسي
  5. يتم إنشاء اتصال ، ويتم إنشاء جلسة جديدة على الخادم ، ويتم تخصيص الذاكرة لمعالجة طلب http
  6. يتم قبول الطلب الوارد عبر بروتوكول http ، ويتم تحليل عنوان URL ، وتتم معالجة المعلمات
  7. ينفذ الوسيطة الخادم
  8. Nuxt تطلق خادم API الخاص بنا
  9. JSON
  10. users.index(), JSON
  11. JSON http
  12. axios JSON
  13. API

تخيل الآن أن لدينا 20 مكونًا في الصفحة تطلب بيانات عبر واجهة برمجة التطبيقات ، لذلك في طلب واحد للصفحة مع خادم Nuxt ، سيتم إنشاء 20 اتصال http داخلي إضافي وسيتم تنفيذ الخطوات 4-13 20 مرة. يمكن لخادم Nuxt HTTP معالجة أكثر من 55 ألف طلب في الثانية ، ومع ذلك ، من خلال إنشاء طلبات HTTP داخلية ، نقوم بتقليل موارد الخادم المحتملة بعشرات المرات.

ولكن عندما نقدم الصفحة على الخادم ، يكون لدينا وصول مباشر إلى جميع وحدات التحكم في المجلد / api /

دعنا نغير المنطق بحيث يتم استدعاء رمز وحدة التحكم مباشرة عند العرض على الخادم ، وعند الاتصال من المتصفح ، يتم إرسال الطلب عبر http

  1. إعادة تسمية الملف /plugins/api-context.js إلى /plugins/api-context.client.js
  2. قم بتغيير اسم الملف في الإعدادات / nuxt.config.js

      plugins: ["~/plugins/api-context.client.js"]
    

    الآن هذا سياق $ Api متاح فقط لرمز العميل
  3. قم بإنشاء سياق $ api للاتصال مباشرة

    بوحدات التحكم على خادم /plugins/api-context.server.js
    export default (context, inject) => {
      inject("api", async (controller, method, params) => {
        try {
          let api = require("../api/" + controller.replace(/^\/+|\/+$|\.+/g, ""));
          return await api[method](params);
        } catch (e) {
          console.error(e);
          throw e;
        }
      });
    };
    
  4. قم بتوصيل البرنامج المساعد

    للخادم / nuxt.config.js
      plugins: [
        "~/plugins/api-context.client.js",
        "~/plugins/api-context.server.js"
      ]
    

الآن وظيفة هذا. $ Api على الخادم سيستدعي مباشرة طريقة تحكم ، وعلى العميل هذا. $ Api يرسل طلب http من خلال المحاور .

الرمز

  async fetch() {
    this.users = await this.$api("users", "index");
  },

عند التقديم على الخادم ، لن يقوم بتنفيذ طلب http لنفسه ، ولكن ببساطة قم بتوصيل ملف /api/users.js عبر طلب واستدعاء طريقة index () ، أي لن يتم تنفيذ العناصر من 4-13 ، ولكن سيتم تنفيذ 10 فقط. ومع ذلك ، عندما ينقر العميل على الزر " تحديث" في المتصفح ، سيتم طلب نفس البيانات عبر http . إليك الكود الكامل: codeandbox.io/s/codesandbox-nuxt-pbriw





اختبار أداء


odesandbox.io/s/codesandbox-nuxt-rzdyw

  1. للقضاء على تأثير سرعة الاتصالات الخارجية ، قمت باستبدال البيانات المستلمة ببيانات ثابتة:

    /api/users.js
    // we can get data from any DB
    async function getDataFromDB() {
      return {
        page: 1,
        per_page: 6,
        total: 12,
        total_pages: 2,
        data: [
          {
            id: 1,
            email: "george.bluth@reqres.in",
            first_name: "George",
            last_name: "Bluth",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
          },
          {
            id: 2,
            email: "janet.weaver@reqres.in",
            first_name: "Janet",
            last_name: "Weaver",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
          },
          {
            id: 3,
            email: "emma.wong@reqres.in",
            first_name: "Emma",
            last_name: "Wong",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg"
          },
          {
            id: 4,
            email: "eve.holt@reqres.in",
            first_name: "Eve",
            last_name: "Holt",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"
          },
          {
            id: 5,
            email: "charles.morris@reqres.in",
            first_name: "Charles",
            last_name: "Morris",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/stephenmoon/128.jpg"
          },
          {
            id: 6,
            email: "tracey.ramos@reqres.in",
            first_name: "Tracey",
            last_name: "Ramos",
            avatar:
              "https://s3.amazonaws.com/uifaces/faces/twitter/bigmancho/128.jpg"
          }
        ],
        ad: {
          company: "StatusCode Weekly",
          url: "http://statuscode.org/",
          text:
            "A weekly newsletter focusing on software development, infrastructure, the server, performance, and the stack end of things."
        }
      };
      /*
      return (await require("axios").get(`https://reqres.in/api/users?page=1`))
        .data;
      */
    }
    ....
    
  2. api , http

    /plugins/api-context.server.js
    export default (context, inject) => {
      inject("server", () => true);
      inject("api", async (controller, method, params) => {
        try {
          if (params && params.httpcall) {
            return await context.$axios["$" + (params ? "post" : "get")](
              "/api/" + controller + "/" + method,
              params
            );
          }
          let api = require("../api/" + controller.replace(/^\/+|\/+$|\.+/g, ""));
          return await api[method](params);
        } catch (e) {
          console.error(e);
          throw e;
        }
      });
    };
    
  3. index.vue fetch api 50

    /pages/index.vue
      async fetch() {
        let start = new Date();
        let promises = [];
        let callNum = 50;
        for (let i = 0; i < callNum; i++) {
          promises.push(this.$api("users", "index"));
        }
    
        let arr = await Promise.all(
          promises.map(async p => {
            return await p;
          })
        );
    
        let res = [];
        for (let r of arr) {
          res = res.concat(r);
        }
    
        this.users = res;
        this.fetchType =
          (this.$server && this.$server() ? "Server internal" : "Client http") +
          " API call";
        this.fetchTime = new Date() - start;
      },
    
  4. httpcall.vue fetch api 50 http

    /pages/httpcall.vue
    ...
          promises.push(this.$api("users", "index", { httpcall: true }));
    ...
        this.fetchType =
          (this.$server && this.$server() ? "Server http" : "Client http") +
          " API call";
    ...
    
  5. قارن الآن وقت تنفيذ rzdyw.sse.codesandbox.io

    خادم استدعاء واجهة برمجة التطبيقات الداخلية لخادم واجهة برمجة التطبيقات: وقت إحضار 1
    مللي

    ثانية من 0 مللي ثانية إلى 2 مللي ثانية كحد أقصى rzdyw.sse.codesandbox.io/httpcall
    Server http API وقت تقديم المكالمات: 71 مللي ثانية
    من 46 مللي ثانية إلى 1059 مللي ثانية كحد أقصى
    وعدة مرات تعطل الخادم بشكل عام مع وجود خطأ

    RangeError
    Maximum call stack size exceeded

هنا مثال كامل - codeandbox.io/s/codesandbox-nuxt-rzdyw

مجموع الجزء 2


  • مع الحد الأدنى من التغييرات ، يمكنك تسريع عرض الخادم بأكثر من 50 مرة ، في مثال مباشر ، تم تسريع عرض صفحتي بمقدار 1.7 مرة تقريبًا
  • تم تقليل موارد خادم عقدة HTTP بشكل ملحوظ
  • بطريقة محسنة ، يجب أن يتحمل مثيل Nuxt الوحيد حمل المشاريع الصغيرة والمتوسطة الحجم

All Articles