Maison  >  Article  >  interface Web  >  Introduction à JavaScript : méthode asyncAdd d'addition asynchrone manuscrite

Introduction à JavaScript : méthode asyncAdd d'addition asynchrone manuscrite

WBOY
WBOYavant
2022-08-26 14:04:132569parcourir

Cet article vous apporte des connaissances pertinentes sur javascript. Il vous présente principalement l'explication détaillée de la méthode asyncAdd d'ajout asynchrone manuscrite de JavaScript. Les amis dans le besoin peuvent s'y référer ensemble. à tout le monde aide.

Introduction à JavaScript : méthode asyncAdd d'addition asynchrone manuscrite

[Recommandations associées : tutoriel vidéo javascript, front-end web]

Avant-propos

J'ai trouvé une question simple mais intéressante sur Nuggets Le titre est le suivant :

// 异步加法
function asyncAdd(a,b,cb){
  setTimeout(() => {
    cb(null, a + b)
  }, Math.random() * 1000)
}
async function total(){
  const res1 = await sum(1,2,3,4,5,6,4)
  const res2 = await sum(1,2,3,4,5,6,4)
  return [res1, res2]
}
total()
// 实现下 sum 函数。注意不能使用加法,在 sum 中借助 asyncAdd 完成加法。尽可能的优化这个方法的时间。
function sum(){
}

Vous, vous pouvez essayer. pour l'implémenter directement et examiner le lien entre votre propre réflexion et les connaissances de base de JavaScript, évitez-le ! JavaScript 基础知识的联系如何,大佬请绕行!

估计大多数人第一眼看下都不知道这题目到底要干啥(我不说就没人知道我也是),但是在看第二遍的时候估计就差不多明白具体是要考察什么内容了,下面就一起来分析分析吧!!!

分析 asyncAdd

这里先放置最终结论:

  • 只能修改 sum 部分的内容,sum 可接收任意长度的参数
  • sum 中只能通过 asyncAdd 实现加法计算
  • sum 中需要处理异步逻辑,需要使用 Promise
  • 需要优化 sum 方法的计算时间

下面是分别通过对代码的不同部分进行分析,获取到的相关的信息。

直观的基本要求

// 实现下 sum 函数。注意不能使用加法,在 sum 中借助 asyncAdd 完成加法。尽可能的优化这个方法的时间。 
function sum(){ }

最直观的方式就是通过上述的文字描述部分,可以很容易知道题目具体要求:

  • 实现 sum 函数,即只能修改 sum 部分的内容
  • 不能直接使用加法(+),通过 asyncAdd 实现加法
  • 优化 sum 方法的计算时间

隐藏的考察点 — setTimeout & cb

// 异步加法
function asyncAdd(a, b, cb){
  setTimeout(() => {
    cb(null, a + b)
  }, Math.random() * 1000)
}

从上述内容来看,最明显的就是 setTimeoutcb 了,其实这不难理解因为在 asyncAdd 中使用了 setTimeout 只能通过回调函数 cb 将本次计算结果返回出去,那其中的第一个参数 null 代表什么呢?

其实可以认为它是一个错误信息对象,如果你比较了解 node 的话,就会知道在 node 中的异步处理的回调函数通常第一个参数就是错误对象,用于传递给外部在发生错误时自定义后续执行逻辑等。

一句话: cb 函数会接收 错误对象 和 计算结果 作为参数传递给外部。

隐藏的考察点 — async & await

async function total(){
  const res1 = await sum(1,2,3,4,5,6,4)
  const res2 = await sum(1,2,3,4,5,6,4)
  return [res1, res2]
}

从上述的这部分来看,sum 方法的 返回值 肯定是一个 promise 类型的,因为最前面明显的使用了 await sum(...) 的形式。

另外 total 函数返回值也必然是一个 promise 类型,因为整个 total 函数被定义为了一个 async 异步函数,可点击此处查看详细内容。

一句话:sum 需要返回 promise 类型的值,即 sum 一定会使用到 promise,并且从 sum(1,2,3,4,5,6,4) 可知 sum 可接收任意长度的参数。

实现 asyncAdd

具体实现

实现思路如下:

  • 考虑到外部参数长度不固定,使用剩余运算符接收所有传入的参数
  • 考虑到 asyncAdd 中的异步操作,将其封装为 Promise 的实现,即 caculate 函数
  • 考虑到 asyncAdd 实际只能一次接收两个数字进行计算,使用循环的形式将多个参数分别传入
  • 考虑到通过循环处理异步操作的顺序问题,使用 async/await 来保证正确的执行顺序,且 async 函数的返回值正好符合 sumPromise 类型的要求

具体代码如下:

// 通过 ES6 的剩余运算符(...) 接收外部传入长度不固定的参数
async function sum(...nums: number[]) {
    // 封装 Promise 
    function caculate(num1: number, num2: number) {
        return new Promise((resolve, reject) => {
            // 调用 asyncAdd 实现加法
            asyncAdd(num1, num2, (err: any, rs: number) => {
                // 处理错误逻辑
                if (err) {
                    reject(err);
                    return;
                }
                // 向外部传递对应的计算结果
                resolve(rs);
            });
        })
    }
    let res: any = 0;
    // 通过遍历将参数一个个进行计算
    for (const n of nums) {
        // 为了避免异步执行顺序问题,使用 await 等待执行结果 
        res = await caculate(res, n);
    }
    return res;
}

进行优化

抽离内层函数

  • caculate 函数可抽离到 sum 函数外层
  • asyncAdd 函数的回调函数没必要抽离,因为它依赖的参数和外部方法太多
function caculate(num1: number, num2: number) {
    return new Promise((resolve, reject) => {
        asyncAdd(num1, num2, (err: any, rs: number) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(rs);
        });
    })
}
async function sum(...nums: number[]) {
    let res: any = 0;
    for (const n of nums) {
        res = await caculate(res, n);
    }
    return res;
}

缓存计算结果

其实你仔细观察 total 方法,其中 sum

Je suppose que la plupart des gens ne savent pas de quoi parle cette question au premier coup d'œil (personne ne me connaît si je ne vous le dis pas), mais après l'avoir lu pour la deuxième fois, je suppose qu'ils comprennent presque quel est le contenu spécifique est à tester. Bon, analysons-le ensemble ! ! !

Analyse de asyncAdd🎜🎜Voici la conclusion finale : 🎜
  • Seul le contenu de la partie sum peut être modifié, et sum peut recevoir des paramètres de n'importe quelle longueur li>
  • somme ne peut implémenter le calcul d'addition que via asyncAdd
  • La logique asynchrone doit être traitée dans somme , qui nécessite l'utilisation de Promesse
  • doit optimiser le temps de calcul de la méthode somme
🎜Le Voici une analyse des différentes parties du code, les informations pertinentes obtenues. 🎜

Exigences de base intuitives

async function total(){
  const res1 = await sum(1,2,3,4,5,6,4)
  const res2 = await sum(1,2,3,4,5,6,4)
  return [res1, res2]
}
🎜La manière la plus intuitive consiste à utiliser la partie de description du texte ci-dessus, vous pouvez facilement connaître les exigences spécifiques de la question : 🎜
  • Atteindre somme code>, c'est-à-dire qu'elle ne peut modifier que le contenu de la partie <code>somme
  • L'addition (+) ne peut pas être utilisée directement, et l'addition est implémentée via asyncAdd
  • Optimiser le temps de calcul de la méthode sum

Point d'inspection caché—setTimeout & cb

const cash: any = {};
function isUndefined(target: any) {
    return target === void 0;
}
async function sum(...nums: number[]) {
    let res: any = 0;
    const key = nums.join(&#39;+&#39;);
    if (!isUndefined(cash[key])) return cash[key];
    for (const n of nums) {
        res = await caculate(res, n);
    }
    cash[key] = res;
    return res;
}
function caculate(num1: number, num2: number) {
    return new Promise((resolve, reject) => {
        asyncAdd(num1, num2, (err: any, rs: number) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(rs);
        });
    })
}
🎜From Dans le contenu ci-dessus, le plus évident est setTimeout et cb. En fait, ce n'est pas difficile à comprendre car setTimeout est utilisé dans asyncAdd et ne peut être transmis que via la fonction de rappel. <code>cb renvoie le résultat de ce calcul. Que représente le premier paramètre null ? 🎜🎜En fait, il peut être considéré comme un objet de message d'erreur. Si vous en savez plus sur node, vous saurez que la fonction de rappel de traitement asynchrone dans node a généralement le premier paramètre C'est l'objet d'erreur, qui est utilisé pour passer à l'extérieur pour personnaliser la logique d'exécution ultérieure lorsqu'une erreur se produit. 🎜🎜Une phrase : La fonction cb recevra l'objet d'erreur et le résultat du calcul en paramètres et les transmettra à l'extérieur. 🎜

Point d'inspection caché - async & wait

rrreee🎜De la partie ci-dessus, la valeur de retour de la méthode sum doit être de type promise Oui, car la forme await sum(...) est clairement utilisée au début. 🎜🎜De plus, la valeur de retour de la fonction total doit également être de type promise, car toute la fonction total est définie comme un async Fonction asynchrone, cliquez ici pour afficher les détails. 🎜🎜Une phrase : sum doit renvoyer une valeur de type promise, c'est-à-dire que sum utilisera certainement promise, et De sum(1,2,3,4,5,6,4) nous pouvons voir que sum peut recevoir des paramètres de n'importe quelle longueur. 🎜🎜Implémenter asyncAdd🎜

Implémentation spécifique

🎜L'idée d'implémentation est la suivante :🎜
  • Considérant que la longueur des paramètres externes n'est pas fixe, utilisez l'opérateur reste pour recevoir tous les paramètres entrants
  • Considérant l'opération asynchrone dans asyncAdd, encapsulez-la comme l'implémentation de Promise, c'est-à-dire la fonction caculer li>
  • Considérant que asyncAdd ne peut en fait recevoir que deux nombres à la fois pour le calcul et utilise une boucle pour transmettre plusieurs paramètres séparément
  • Considérant l'ordre de traitement des opérations asynchrones à travers les boucles, utilisez async/await pour garantir la séquence d'exécution correcte, et la valeur de retour de la fonction async correspond exactement à la somme et est de les exigences de type Promesse
🎜Le code spécifique est le suivant :🎜rrreee

Optimiser

Extraire les fonctions internes

  • caculer La fonction peut être extraite vers la couche externe de la fonction sum
  • asyncAdd La fonction de rappel de la fonction n'a pas besoin d'être extraite car elle s'appuie sur trop de paramètres et de méthodes externes Multi
rrreee

Résultats du calcul du cache

🎜En fait, si vous observez attentivement le total, sum est appelé deux fois, et Les paramètres sont toujours exactement les mêmes, et le but est de vous rappeler que lors du calcul du même contenu pour la deuxième fois, les résultats sont obtenus directement à partir du cache, plutôt que via un calcul asynchrone. 🎜rrreee🎜Ce qui suit n'est qu'une implémentation d'une solution de mise en cache simple. Ne vous inquiétez pas trop. L'implémentation spécifique est la suivante : 🎜
const cash: any = {};
function isUndefined(target: any) {
    return target === void 0;
}
async function sum(...nums: number[]) {
    let res: any = 0;
    const key = nums.join(&#39;+&#39;);
    if (!isUndefined(cash[key])) return cash[key];
    for (const n of nums) {
        res = await caculate(res, n);
    }
    cash[key] = res;
    return res;
}
function caculate(num1: number, num2: number) {
    return new Promise((resolve, reject) => {
        asyncAdd(num1, num2, (err: any, rs: number) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(rs);
        });
    })
}

【相关推荐:javascript视频教程web前端

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer