<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【JS】891- 高級 Promise 模式 - Promise緩存

          共 3387字,需瀏覽 7分鐘

           ·

          2021-03-11 18:55

          https://www.jonmellman.com/posts/promise-memoization  譯者:ConardLi

          本文中,我們將介紹常見的緩存實現(xiàn)在并發(fā)條件下存在的問題。然后我們將介紹如何修復(fù)它,并且在此過程中簡化代碼。

          我們將通過介紹基于 Singleton Promise 模式的 Promise Memoization 模式來做到這一點。

          Singleton Promise 模式看前面的文章:高級異步模式 - Promise 單例

          一個例子:緩存異步請求結(jié)果

          下面是一個簡單的 API 客戶端:

          const getUserById = async (userId: string): Promise<User> => {
            const user = await request.get(`https://users-service/${userId}`);
            return user;
          };

          非常簡單。

          但是,如果要關(guān)注性能,該怎么辦?users-service 解析用戶詳細信息可能很慢,也許我們經(jīng)常使用相同的用戶 ID 集來調(diào)用此方法。

          我們可能要添加緩存,該怎么做?

          簡單的解決方案

          const usersCache = new Map<string, User>();

          const getUserById = async (userId: string): Promise<User> => {
            if (!usersCache.has(userId)) {
              const user = await request.get(`https://users-service/${userId}`);
              usersCache.set(userId, user);
            }

            return usersCache.get(userId);
          };

          這非常簡單:在從 users-service 中解析了用戶詳細信息之后將結(jié)果填充到內(nèi)存中的緩存中。

          并發(fā)場景

          上面的代碼,它將在以下情況下進行重復(fù)的網(wǎng)絡(luò)調(diào)用:

          await Promise.all([
            getUserById('user1'),
            getUserById('user1')
          ]);

          問題在于直到第一個調(diào)用解決后,我們才分配緩存。但是,等等,如何在獲得結(jié)果之前填充緩存?

          如果我們緩存結(jié)果的 Promise 而不是結(jié)果本身,該怎么辦?代碼如下:

          const userPromisesCache = new Map<string, Promise<User>>();

          const getUserById = (userId: string): Promise<User> => {
            if (!userPromisesCache.has(userId)) {
              const userPromise = request.get(`https://users-service/v1/${userId}`);
              userPromisesCache.set(userId, userPromise);
            }

            return userPromisesCache.get(userId)!;
          };

          非常相似,但是我們沒有 await 發(fā)出網(wǎng)絡(luò)請求,而是將其 Promise 放入緩存中,然后將其返回給調(diào)用方。

          注意,我們不需要聲明我們的方法 async ,因為它不再調(diào)用 await 。我們的方法簽名雖然沒有改變我們?nèi)匀环祷匾粋€ promise ,但是我們是同步進行的。

          這樣可以解決并發(fā)條件,無論時間如何,當我們對進行多次調(diào)用時,只會觸發(fā)一個網(wǎng)絡(luò)請求 getUserById('user1')。這是因為所有后續(xù)調(diào)用者都收到與第一個相同的 Promise 單例。

          Promise 緩存

          從另一個角度看,我們的最后一個緩存實現(xiàn)實際上只是在記憶 getUserById!給定我們已經(jīng)看到的輸入后,我們只返回存儲的結(jié)果(恰好是一個Promise)。

          因此,記住我們的異步方法可以使我們在沒有競爭條件的情況下進行緩存。

          借助 lodash,我們可以將最后一個解決方案簡化為:

          import _ from 'lodash';

          const getUserById = _.memoize(async (userId: string): Promise<User> => {
            const user = await request.get(`https://users-service/${userId}`);
            return user;
          });

          我們采用了原始的無緩存實現(xiàn),并放入了 _.memoize 包裝器,非常簡潔。

          錯誤處理

          對于 API 客戶端,你應(yīng)考慮操作可能失敗的可能性。如果我們的內(nèi)存實現(xiàn)已緩存了被拒絕的 Promise ,則所有將來的調(diào)用都將以同樣的失敗 Promise 被拒絕!

          幸運的是,memoizee(https://www.npmjs.com/package/memoizee) 庫支持此功能。我們的最后一個示例變?yōu)椋?/p>

          import memoize from 'memoizee';

          const getUserById = memoize(async (userId: string): Promise<User> => {
            const user = await request.get(`https://users-service/${userId}`);
            return user;
          }, { promisetrue});

          本文完。

          1. JavaScript 重溫系列(22篇全)
          2. ECMAScript 重溫系列(10篇全)
          3. JavaScript設(shè)計模式 重溫系列(9篇全)
          4. 正則 / 框架 / 算法等 重溫系列(16篇全)
          5. Webpack4 入門(上)|| Webpack4 入門(下)
          6. MobX 入門(上) ||  MobX 入門(下)
          7. 100+篇原創(chuàng)系列匯總

          回復(fù)“加群”與大佬們一起交流學習~

          點擊“閱讀原文”查看 100+ 篇原創(chuàng)文章

          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  最好看2019中文在线播放电影 | 高清无码操逼视频 | 男人天堂久草视频 | 成人自拍在线观看 | 无码电影视频 |