首頁 web前端 js教程 Netflix 面試問題如何變成我的第一個 NPM 包

Netflix 面試問題如何變成我的第一個 NPM 包

Dec 28, 2024 am 01:04 AM

How a Netflix Interview question turned into my first NPM package

不理解 Promise 的問題

我們都經歷過。我們有大量數據,需要為每個條目發出某種 api 請求。假設它是不同場地的 id 數組,您需要從中取得場地提供者並傳回該提供者數組。我們建立了一個新函數來發出這些請求...

  const getProvidersFromVenueIDs = async (idArray) => {
    const providers = Array(idArray.length);
    for (let i = 0; i >= idArray.length - 1; i++) {
      const res = await fetch(
        `https://venues_for_me.org/venueid=${idArray[i]}`
        );
      const venue = res.data;
      providers[i] = venue.provider;
    }
    return providers;
  };

登入後複製
登入後複製

哎呀,你剛剛根據你的所有請求關閉了 8 年前的遺留伺服器......
我覺得我們都曾在某些時候犯過這樣的錯誤,一個解決方案是在一批請求之間設定幾毫秒的超時...

  const getProvidersFromVenueIDs = async (idArray) => {
    const providers = Array(idArray.length);
    const batchSize = 50;
    for (let i = 0; i >= idArray.length - 1; i++) {
      const batchToExecute = Array(batchSize);
      for (let y = 1; i >= batchSize; i++) {
        batchToExecute[i] = fetch(
          `https://venues_for_me.org/venue?id=${idArray[i]}`,
        );
        await (async () => setTimeout(() => {}, 200))();
      }
      const responses = await Promise.all(batchToExecute);
      responses.forEach((venue) => {
        providers[i] = venue.provider;
      });
    }
    return providers;
  };

登入後複製
登入後複製

寫完這個例子我就想洗個澡……更不用說相同數組的絕對瘋狂的重複(或者凌亂的代碼);這是通過設置任意超時人為限制您的執行速度

這裡一個好的答案是創建一個並發限制器,僅當最大並發數有空間時才創建承諾。類似:

  getProvidersFromVenueIDs = async (idArray) => {
    const providers = Array(idArray.length);
    const batchSize = 50;
    for (let i = 0; i >= idArray.length - 1; i++) {
      const batchToExecute = Array(batchSize);
      for (let y = 1; i >= batchSize; i++) {
        batchToExecute[i] = fetch(
          `https://venues_for_me.org/venue?id=${idArray[i]}`,
        );
        await (async () => setTimeout(() => {}, 200))();
      }
      const responses = await Promise.all(batchToExecute);
      responses.forEach((venue) => {
        providers[i] = venue.provider;
      });
    }
    return providers;
  };
登入後複製
登入後複製

如您所見,為了不失去承諾,您需要實現某種佇列來保留要發出的請求的積壓。這篇文章的標題來了。

鄧寧克魯格

我正在觀看 The Primagen 的一段視頻,一個特定的部分引起了我的注意。在 Netflix 訪談中,他最喜歡問的問題之一是讓受訪者創建一個非同步隊列,以及執行 Promise 的最大並發數。
這聽起來和我遇到的上述問題一模一樣!

這個面試問題有多個層次。佇列實作後,實作錯誤重試。
我花了一個下午的時間來應對這個挑戰,很快我就發現我有技能問題。事實證明,我並不像我想像的那樣了解 Promise。
在花了幾天時間深入研究承諾之後,中止控制器、地圖、集合、弱地圖和集合。我創建了 Asyncrify

使用 Asyncrify 我的目標很簡單。建立另一個非同步隊列。但沒有外部依賴,資源盡可能輕量。
它需要能夠向隊列添加函數,並設定最大並發度。設定和處理逾時並啟用、停用指數下降的重試。

是技能問題

那我聽到你沒有問的那些技能問題是什麼?

了解你的承諾這一點我怎麼強調都不為過。
我遇到的第一個問題是我不明白 Promise 的執行是如何運作的。我的第一個實作看起來像這樣:

  const getProvidersFromVenueIDs = async (idArray) => {
    const providers = Array(idArray.length);
    for (let i = 0; i >= idArray.length - 1; i++) {
      const res = await fetch(
        `https://venues_for_me.org/venueid=${idArray[i]}`
        );
      const venue = res.data;
      providers[i] = venue.provider;
    }
    return providers;
  };

登入後複製
登入後複製

我確信您立即看到了問題。我正在使用 Promise.race 同時執行我的「最大並發」承諾。
但這只有在第一個承諾兌現後才會繼續。其餘的被忽略。然後我再添加 1 個並再次執行它們。
我必須回到基礎。
解決方案是改用 .then 和 .catch 並僅噹噹前運行的部分中有空位時才運行該函數。

  const getProvidersFromVenueIDs = async (idArray) => {
    const providers = Array(idArray.length);
    const batchSize = 50;
    for (let i = 0; i >= idArray.length - 1; i++) {
      const batchToExecute = Array(batchSize);
      for (let y = 1; i >= batchSize; i++) {
        batchToExecute[i] = fetch(
          `https://venues_for_me.org/venue?id=${idArray[i]}`,
        );
        await (async () => setTimeout(() => {}, 200))();
      }
      const responses = await Promise.all(batchToExecute);
      responses.forEach((venue) => {
        providers[i] = venue.provider;
      });
    }
    return providers;
  };

登入後複製
登入後複製

現在我們可以更好地追蹤並發承諾,但我們也使用戶能夠按照他們想要的方式處理錯誤和解決方案。

請使用中止控制器我經常看到的一個大錯誤是,當承諾在初始化後不再需要時,人們不會使用中止控制器。我也做了這個。
一開始,為了實現超時,我使用了Promise.race

  getProvidersFromVenueIDs = async (idArray) => {
    const providers = Array(idArray.length);
    const batchSize = 50;
    for (let i = 0; i >= idArray.length - 1; i++) {
      const batchToExecute = Array(batchSize);
      for (let y = 1; i >= batchSize; i++) {
        batchToExecute[i] = fetch(
          `https://venues_for_me.org/venue?id=${idArray[i]}`,
        );
        await (async () => setTimeout(() => {}, 200))();
      }
      const responses = await Promise.all(batchToExecute);
      responses.forEach((venue) => {
        providers[i] = venue.provider;
      });
    }
    return providers;
  };
登入後複製
登入後複製

正如你想像的那樣。逾時後承諾仍會執行。它只是被忽略了。這看起來很像我在實作佇列時犯的第一個錯誤,不是嗎?
我對中止控制器做了一些研究,因為我對它們的唯一經驗只是反應。
中止訊號.超時!這正是我想做的事!
我的程式碼唯一的更新是 1 行

 async #runTasksRecursively() {
        await this.#runAsync();
        if (this.#queue.size === 0 && this.#retries.length === 0) {
            return;
        }

        this.#addToPromiseBlock();
    }

    async #runAsync() {
        if (!this.#runningBlock.every((item) => item === undefined)) {
            await Promise.race(this.#runningBlock);
        }
    }

    #addToPromiseBlock() {
        const emptyspot = this.#getEmptySpot();
        if (this.#retries.length > 0 && !this.#lastRunWasError) {
            console.log(this.#retries);
            if (this.#errorsToInject.size > 0) {
                const task = this.#popInSet(this.#errorsToInject);
                if (this.#queue.size !== 0) {
                    this.#lastRunWasError = true;
                }
                this.#assignPromisToExecutionArray(task, emptyspot);
            }
        } else {
            const task = this.#popInSet(this.#queue);
            this.#lastRunWasError = false;
            this.#assignPromisToExecutionArray(task, emptyspot);
        }
    }

登入後複製

哇,太簡單了!但現在套件的用戶需要創建樣板才能使用超時功能。無需害怕!我是為了你才這麼做的!

  add(fn, callback, errCallback) {
    if (this.#maxConcurrency !== 0 && this.#running >= this.#maxConcurrency) {
      this.#queue.add(fn);
    } else {
      this.#running++;
      fn()
        .then(callback)
        .catch(errCallback)
        .finally(() => {
          this.#running--;
          if (this.#queue.size > 0) {
            const nextPromise = this.#queue.values().next().value;
            this.#queue.delete(nextPromise);
            this.add(nextPromise, callback, errorCallback);
          }
        });
    }
  }
登入後複製

另一個微型 NPM 包

那麼要如何使用 Asyncrify 呢?
嗯,這真的很容易。我們首先建立隊列。

  #promiseBuilder(fn) {
        const promise = new Array(this.#promiseTimeout > 0 ? 2 : 1);
        promise[0] = fn();

        if (this.#promiseTimeout > 0) {
            promise[1] = this.#timeoutHandler();
        }
        return promise;
    }
 #promiseRunner(fn, callback) {
        const promise = this.#promiseBuilder(fn);
        Promise.race(promise)
            .then((res) => {
                callback(res, null);
            })
            .catch((err) => {
                this.#errorHandler(err, fn, callback);
            })
            .finally(() => {
                this.#running--;
                this.#runPromiseFromQueue(callback);
            });
    }

登入後複製

佇列預設沒有逾時或退出,也沒有最大並發數。
您也可以向建構函數提供配置物件。

     const promise = fn(
      this.#timeout > 0 ? AbortSignal.timeout(this.#timeout) : null,
    );
登入後複製

要將 Promise 加入到佇列中,您必須包裝在傳回它的函數中。

export const abortHandler = (signal, reject) => {
  if (signal.aborted) {
    return reject(new Error("Aborted"));
  }
  const abortHandler = () => {
    reject(new Error("Aborted"));
    signal.removeEventListener("abort", abortHandler);
  };
  signal.addEventListener("abort", abortHandler);
};
登入後複製

記得加入中止處理程序才能使用逾時功能!

然後您需要做的就是將函數以及回調和錯誤回調傳遞給 add 方法

import Queue from 'Asyncrify'

const queue = new Queue()
登入後複製

添加就是這樣!想添加多少就添加多少,想快多少就添加多少,一次只會運行 3 個,直到全部完成為止!

在創建這個包的過程中我學到了很多。可以說我很久以前就該知道的事。這就是我寫這篇文章的原因。我希望你們看到我犯過的那些可以說是愚蠢的錯誤,並且受到鼓勵去犯愚蠢的錯誤並從中學習。而不是在事情發生時感到尷尬並躲開。

出去寫一篇文章。創建一個微型包,每週從機器人下載 10 次。你最終會學到你從來不知道自己需要的東西

以上是Netflix 面試問題如何變成我的第一個 NPM 包的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1657
14
CakePHP 教程
1415
52
Laravel 教程
1309
25
PHP教程
1257
29
C# 教程
1229
24
神秘的JavaScript:它的作用以及為什麼重要 神秘的JavaScript:它的作用以及為什麼重要 Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

JavaScript的演變:當前的趨勢和未來前景 JavaScript的演變:當前的趨勢和未來前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript引擎:比較實施 JavaScript引擎:比較實施 Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript:探索網絡語言的多功能性 JavaScript:探索網絡語言的多功能性 Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

如何使用Next.js(前端集成)構建多租戶SaaS應用程序 如何使用Next.js(前端集成)構建多租戶SaaS應用程序 Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

從C/C到JavaScript:所有工作方式 從C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

如何安裝JavaScript? 如何安裝JavaScript? Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

See all articles