Maison interface Web js tutoriel Le contrôle de flux asynchrone Node.js expliqué en détail

Le contrôle de flux asynchrone Node.js expliqué en détail

Jan 22, 2018 am 10:11 AM
javascript node.js 详解

Quand on n'a pas une expérience approfondie de l'utilisation des rappels de fonctions, il est quand même un peu difficile de lire ces contenus. En raison des caractéristiques asynchrones uniques de Node.js, le problème de « l'enfer des rappels » est apparu. Dans cet article, j'ai enregistré plus en détail comment résoudre le problème du flux asynchrone. Cet article présente principalement une brève discussion sur le contrôle de flux asynchrone dans Node.js. L'éditeur pense que c'est assez bon, je vais donc le partager avec vous maintenant et le donner comme référence. Suivons l'éditeur et jetons un œil. J'espère que cela pourra aider tout le monde.

L'article sera long, et cet article est une explication du mode streaming asynchrone. Cet article utilisera un exemple simple d'araignée Web. Sa fonction est d'explorer le contenu de la page Web de l'URL spécifiée et de l'enregistrer dans le projet. À la fin de l'article, vous pouvez trouver la démo du code source de l'article entier.

1. Mode JavaScript natif

Cet article n'est pas destiné aux débutants, la plupart du contenu de base sera donc omis :

(spider_v1 .js )


const request = require("request");
const fs = require("fs");
const mkdirp = require("mkdirp");
const path = require("path");
const utilities = require("./utilities");

function spider(url, callback) {
  const filename = utilities.urlToFilename(url);
  console.log(`filename: ${filename}`);

  fs.exists(filename, exists => {
    if (!exists) {
      console.log(`Downloading ${url}`);

      request(url, (err, response, body) => {
        if (err) {
          callback(err);
        } else {
          mkdirp(path.dirname(filename), err => {
            if (err) {
              callback(err);
            } else {
              fs.writeFile(filename, body, err => {
                if (err) {
                  callback(err);
                } else {
                  callback(null, filename, true);
                }
              });
            }
          });
        }
      });
    } else {
      callback(null, filename, false);
    }
  });
}

spider(process.argv[2], (err, filename, downloaded) => {
  if (err) {
    console.log(err);
  } else if (downloaded) {
    console.log(`Completed the download of ${filename}`);
  } else {
    console.log(`${filename} was already downloaded`);
  }
});
Copier après la connexion

Le processus du code ci-dessus ressemble à ceci :

  1. Convertir l'URL en nom de fichier

  2. Déterminez si le nom du fichier existe, et revenez directement s'il existe, sinon passez à l'étape suivante

  3. Envoyez une demande et récupérez le corps

  4. Écrivez le corps dans le fichier

Il s'agit d'une version très simple de l'araignée. Elle ne peut explorer que le contenu d'une URL. le rappel ci-dessus est. Les gens ont des maux de tête. Ensuite, nous commençons à optimiser.

Tout d'abord, la méthode if else peut être optimisée. C'est très simple. Inutile de dire que voici un effet de comparaison :


/// before
if (err) {
  callback(err);
} else {
  callback(null, filename, true);
}

/// after
if (err) {
  return callback(err);
}
callback(null, filename, true);
Copier après la connexion
<🎜. >Le code est le suivant En écriture, il y aura une couche d'imbrication en moins, mais les programmeurs expérimentés penseront qu'écrire de cette façon met trop l'accent sur les erreurs. Notre programmation devrait se concentrer sur le traitement des données correctes, et il existe également une telle méthode. exigence de lisibilité.

Une autre optimisation est le fractionnement des fonctions. Dans la fonction araignée du code ci-dessus, le fichier téléchargé et le fichier enregistré peuvent être divisés.

(spider_v2.js)


const request = require("request");
const fs = require("fs");
const mkdirp = require("mkdirp");
const path = require("path");
const utilities = require("./utilities");

function saveFile(filename, contents, callback) {
  mkdirp(path.dirname(filename), err => {
    if (err) {
      return callback(err);
    }
    fs.writeFile(filename, contents, callback);
  });
}

function download(url, filename, callback) {
  console.log(`Downloading ${url}`);

  request(url, (err, response, body) => {
    if (err) {
      return callback(err);
    }
    saveFile(filename, body, err => {
      if (err) {
        return callback(err);
      }
      console.log(`Downloaded and saved: ${url}`);
      callback(null, body);
    });
  })
}

function spider(url, callback) {
  const filename = utilities.urlToFilename(url);
  console.log(`filename: ${filename}`);

  fs.exists(filename, exists => {
    if (exists) {
      return callback(null, filename, false);
    }
    download(url, filename, err => {
      if (err) {
        return callback(err);
      }
      callback(null, filename, true);
    })
  });
}

spider(process.argv[2], (err, filename, downloaded) => {
  if (err) {
    console.log(err);
  } else if (downloaded) {
    console.log(`Completed the download of ${filename}`);
  } else {
    console.log(`${filename} was already downloaded`);
  }
});
Copier après la connexion
Le code ci-dessus est essentiellement le résultat d'une optimisation native, mais la fonction de cette araignée est trop simple, nous devons maintenant explorer toutes les URL d'une certaine page Web, ce qui entraînera des problèmes en série et en parallèle.

(spider_v3.js)


const request = require("request");
const fs = require("fs");
const mkdirp = require("mkdirp");
const path = require("path");
const utilities = require("./utilities");

function saveFile(filename, contents, callback) {
  mkdirp(path.dirname(filename), err => {
    if (err) {
      return callback(err);
    }
    fs.writeFile(filename, contents, callback);
  });
}

function download(url, filename, callback) {
  console.log(`Downloading ${url}`);

  request(url, (err, response, body) => {
    if (err) {
      return callback(err);
    }
    saveFile(filename, body, err => {
      if (err) {
        return callback(err);
      }
      console.log(`Downloaded and saved: ${url}`);
      callback(null, body);
    });
  })
}

/// 最大的启发是实现了如何异步循环遍历数组
function spiderLinks(currentUrl, body, nesting, callback) {
  if (nesting === 0) {
    return process.nextTick(callback);
  }

  const links = utilities.getPageLinks(currentUrl, body);

  function iterate(index) {
    if (index === links.length) {
      return callback();
    }
    spider(links[index], nesting - 1, err => {
      if (err) {
        return callback(err);
      }
      iterate((index + 1));
    })
  }

  iterate(0);
}

function spider(url, nesting, callback) {
  const filename = utilities.urlToFilename(url);

  fs.readFile(filename, "utf8", (err, body) => {
    if (err) {
      if (err.code !== &#39;ENOENT&#39;) {
        return callback(err);
      }
      return download(url, filename, (err, body) => {
        if (err) {
          return callback(err);
        }
        spiderLinks(url, body, nesting, callback);
      });
    }

    spiderLinks(url, body, nesting, callback);
  });
}

spider(process.argv[2], 2, (err, filename, downloaded) => {
  if (err) {
    console.log(err);
  } else if (downloaded) {
    console.log(`Completed the download of ${filename}`);
  } else {
    console.log(`${filename} was already downloaded`);
  }
});
Copier après la connexion
Le code ci-dessus a deux fonctions principales de plus que le code précédent. La première est de l'obtenir via le. classe auxiliaire Lorsqu'il s'agit de liens dans un certain corps :


const links = utilities.getPageLinks(currentUrl, body);
Copier après la connexion
L'implémentation interne ne sera pas expliquée. L'autre code de base est :

.


/// 最大的启发是实现了如何异步循环遍历数组
function spiderLinks(currentUrl, body, nesting, callback) {
  if (nesting === 0) {
    return process.nextTick(callback);
  }

  const links = utilities.getPageLinks(currentUrl, body);

  function iterate(index) {
    if (index === links.length) {
      return callback();
    }
    spider(links[index], nesting - 1, err => {
      if (err) {
        return callback(err);
      }
      iterate((index + 1));
    })
  }

  iterate(0);
}
Copier après la connexion
On peut dire que le petit morceau de code ci-dessus est un modèle natif pour implémenter la sérialisation asynchrone. En plus de cela, le concept d'imbrication est également introduit. Grâce à cet attribut, le niveau d'exploration peut être contrôlé.

À ce stade, nous avons complètement implémenté la fonction série. Compte tenu des performances, nous devons développer la fonction d'exploration parallèle.

(spider_v4.js)


const request = require("request");
const fs = require("fs");
const mkdirp = require("mkdirp");
const path = require("path");
const utilities = require("./utilities");

function saveFile(filename, contents, callback) {
  mkdirp(path.dirname(filename), err => {
    if (err) {
      return callback(err);
    }
    fs.writeFile(filename, contents, callback);
  });
}

function download(url, filename, callback) {
  console.log(`Downloading ${url}`);

  request(url, (err, response, body) => {
    if (err) {
      return callback(err);
    }
    saveFile(filename, body, err => {
      if (err) {
        return callback(err);
      }
      console.log(`Downloaded and saved: ${url}`);
      callback(null, body);
    });
  })
}

/// 最大的启发是实现了如何异步循环遍历数组
function spiderLinks(currentUrl, body, nesting, callback) {
  if (nesting === 0) {
    return process.nextTick(callback);
  }

  const links = utilities.getPageLinks(currentUrl, body);
  if (links.length === 0) {
    return process.nextTick(callback);
  }

  let completed = 0, hasErrors = false;

  function done(err) {
    if (err) {
      hasErrors = true;
      return callback(err);
    }

    if (++completed === links.length && !hasErrors) {
      return callback();
    }
  }

  links.forEach(link => {
    spider(link, nesting - 1, done);
  });
}

const spidering = new Map();

function spider(url, nesting, callback) {
  if (spidering.has(url)) {
    return process.nextTick(callback);
  }

  spidering.set(url, true);

  const filename = utilities.urlToFilename(url);

  /// In this pattern, there will be some issues.
  /// Possible problems to download the same url again and again。
  fs.readFile(filename, "utf8", (err, body) => {
    if (err) {
      if (err.code !== &#39;ENOENT&#39;) {
        return callback(err);
      }
      return download(url, filename, (err, body) => {
        if (err) {
          return callback(err);
        }
        spiderLinks(url, body, nesting, callback);
      });
    }

    spiderLinks(url, body, nesting, callback);
  });
}

spider(process.argv[2], 2, (err, filename, downloaded) => {
  if (err) {
    console.log(err);
  } else if (downloaded) {
    console.log(`Completed the download of ${filename}`);
  } else {
    console.log(`${filename} was already downloaded`);
  }
});
Copier après la connexion
Ce code est également très simple et a deux contenus principaux. La première est de savoir comment implémenter la concurrence :


/// 最大的启发是实现了如何异步循环遍历数组
function spiderLinks(currentUrl, body, nesting, callback) {
  if (nesting === 0) {
    return process.nextTick(callback);
  }

  const links = utilities.getPageLinks(currentUrl, body);
  if (links.length === 0) {
    return process.nextTick(callback);
  }

  let completed = 0, hasErrors = false;

  function done(err) {
    if (err) {
      hasErrors = true;
      return callback(err);
    }

    if (++completed === links.length && !hasErrors) {
      return callback();
    }
  }

  links.forEach(link => {
    spider(link, nesting - 1, done);
  });
}
Copier après la connexion
Le code ci-dessus peut être considéré comme un modèle pour atteindre la concurrence. Ceci est réalisé en utilisant le parcours de boucle. Un autre élément essentiel est que, comme il est simultané, il y aura des problèmes lors de l'utilisation de fs.exists et le même fichier peut être téléchargé à plusieurs reprises. La solution ici est :


  • Utiliser Map To. mettre en cache une certaine URL, l'URL doit être utilisée comme clé

Nous avons maintenant de nouvelles exigences, qui nécessitent de limiter le nombre maximum de simultanéités simultanées, nous en introduisons donc ici une qui, je pense, est la Concept le plus important : file d’attente.

(task-Queue.js)


class TaskQueue {
  constructor(concurrency) {
    this.concurrency = concurrency;
    this.running = 0;
    this.queue = [];
  }

  pushTask(task) {
    this.queue.push(task);
    this.next();
  }

  next() {
    while (this.running < this.concurrency && this.queue.length) {
      const task = this.queue.shift();
      task(() => {
        this.running--;
        this.next();
      });
      this.running++;
    }
  }
}

module.exports = TaskQueue;
Copier après la connexion
Le code ci-dessus est le code d'implémentation de la file d'attente. Le noyau est la méthode next(). , comme vous pouvez le voir, lorsque la tâche est ajoutée à la file d'attente, elle sera exécutée immédiatement. Cela ne signifie pas que la tâche doit être exécutée immédiatement, mais cela signifie que next sera appelé immédiatement.

(spider_v5.js)


const request = require("request");
const fs = require("fs");
const mkdirp = require("mkdirp");
const path = require("path");
const utilities = require("./utilities");
const TaskQueue = require("./task-Queue");
const downloadQueue = new TaskQueue(2);

function saveFile(filename, contents, callback) {
  mkdirp(path.dirname(filename), err => {
    if (err) {
      return callback(err);
    }
    fs.writeFile(filename, contents, callback);
  });
}

function download(url, filename, callback) {
  console.log(`Downloading ${url}`);

  request(url, (err, response, body) => {
    if (err) {
      return callback(err);
    }
    saveFile(filename, body, err => {
      if (err) {
        return callback(err);
      }
      console.log(`Downloaded and saved: ${url}`);
      callback(null, body);
    });
  })
}

/// 最大的启发是实现了如何异步循环遍历数组
function spiderLinks(currentUrl, body, nesting, callback) {
  if (nesting === 0) {
    return process.nextTick(callback);
  }

  const links = utilities.getPageLinks(currentUrl, body);
  if (links.length === 0) {
    return process.nextTick(callback);
  }

  let completed = 0, hasErrors = false;

  links.forEach(link => {
    /// 给队列出传递一个任务,这个任务首先是一个函数,其次该函数接受一个参数
    /// 当调用任务时,触发该函数,然后给函数传递一个参数,告诉该函数在任务结束时干什么
    downloadQueue.pushTask(done => {
      spider(link, nesting - 1, err => {
        /// 这里表示,只要发生错误,队列就会退出
        if (err) {
          hasErrors = true;
          return callback(err);
        }
        if (++completed === links.length && !hasErrors) {
          callback();
        }

        done();
      });
    });

  });
}

const spidering = new Map();

function spider(url, nesting, callback) {
  if (spidering.has(url)) {
    return process.nextTick(callback);
  }

  spidering.set(url, true);

  const filename = utilities.urlToFilename(url);

  /// In this pattern, there will be some issues.
  /// Possible problems to download the same url again and again。
  fs.readFile(filename, "utf8", (err, body) => {
    if (err) {
      if (err.code !== &#39;ENOENT&#39;) {
        return callback(err);
      }
      return download(url, filename, (err, body) => {
        if (err) {
          return callback(err);
        }
        spiderLinks(url, body, nesting, callback);
      });
    }

    spiderLinks(url, body, nesting, callback);
  });
}

spider(process.argv[2], 2, (err, filename, downloaded) => {
  if (err) {
    console.log(`error: ${err}`);
  } else if (downloaded) {
    console.log(`Completed the download of ${filename}`);
  } else {
    console.log(`${filename} was already downloaded`);
  }
});
Copier après la connexion
Par conséquent, afin de limiter le nombre de concurrence, mettez simplement le parcours des tâches dans la méthode spiderLinks La file d'attente fera l'affaire. C'est relativement simple.

Jusqu'à présent, nous avons utilisé JavaScript natif pour implémenter un web spider avec des fonctions relativement complètes, qui peuvent être à la fois série et simultanées, et peuvent également contrôler le nombre de concurrences.

2. Utilisez la bibliothèque asynchrone

Mettre différentes fonctions dans différentes fonctions nous apportera d'énormes avantages La bibliothèque asynchrone est très populaire et ses performances sont également bonnes, il est basé sur le rappel en interne.

(spider_v6.js)


const request = require("request");
const fs = require("fs");
const mkdirp = require("mkdirp");
const path = require("path");
const utilities = require("./utilities");
const series = require("async/series");
const eachSeries = require("async/eachSeries");

function download(url, filename, callback) {
  console.log(`Downloading ${url}`);

  let body;

  series([
    callback => {
      request(url, (err, response, resBody) => {
        if (err) {
          return callback(err);
        }
        body = resBody;
        callback();
      });
    },
    mkdirp.bind(null, path.dirname(filename)),
    callback => {
      fs.writeFile(filename, body, callback);
    }
  ], err => {
    if (err) {
      return callback(err);
    }
    console.log(`Downloaded and saved: ${url}`);
    callback(null, body);
  });
}

/// 最大的启发是实现了如何异步循环遍历数组
function spiderLinks(currentUrl, body, nesting, callback) {
  if (nesting === 0) {
    return process.nextTick(callback);
  }

  const links = utilities.getPageLinks(currentUrl, body);
  if (links.length === 0) {
    return process.nextTick(callback);
  }

  eachSeries(links, (link, cb) => {
    "use strict";
    spider(link, nesting - 1, cb);
  }, callback);
}

const spidering = new Map();

function spider(url, nesting, callback) {
  if (spidering.has(url)) {
    return process.nextTick(callback);
  }

  spidering.set(url, true);

  const filename = utilities.urlToFilename(url);

  fs.readFile(filename, "utf8", (err, body) => {
    if (err) {
      if (err.code !== &#39;ENOENT&#39;) {
        return callback(err);
      }
      return download(url, filename, (err, body) => {
        if (err) {
          return callback(err);
        }
        spiderLinks(url, body, nesting, callback);
      });
    }

    spiderLinks(url, body, nesting, callback);
  });
}

spider(process.argv[2], 1, (err, filename, downloaded) => {
  if (err) {
    console.log(err);
  } else if (downloaded) {
    console.log(`Completed the download of ${filename}`);
  } else {
    console.log(`${filename} was already downloaded`);
  }
});
Copier après la connexion
Dans le code ci-dessus, nous n'utilisons que trois fonctions async :


const series = require("async/series"); // 串行
const eachSeries = require("async/eachSeries"); // 并行
const queue = require("async/queue"); // 队列
Copier après la connexion
Comme c'est relativement simple, je ne l'expliquerai pas. Le code de la file d'attente en asynchrone se trouve dans (spider_v7.js), qui est très similaire à notre file d'attente personnalisée ci-dessus, et je ne l'expliquerai pas davantage.

3.Promise

Promise est un protocole Il existe de nombreuses bibliothèques qui implémentent ce protocole. Nous utilisons l'implémentation ES6. En termes simples, une promesse est un accord. Si elle est terminée, sa méthode de résolution est appelée. Si elle échoue, sa méthode de rejet est appelée. Il implémente la méthode then, puis renvoie la promesse elle-même, formant ainsi une chaîne d'appels.

其实Promise的内容有很多,在实际应用中是如何把普通的函数promise化。这方面的内容在这里也不讲了,我自己也不够格

(spider_v8.js)


const utilities = require("./utilities");
const request = utilities.promisify(require("request"));
const fs = require("fs");
const readFile = utilities.promisify(fs.readFile);
const writeFile = utilities.promisify(fs.writeFile);
const mkdirp = utilities.promisify(require("mkdirp"));
const path = require("path");


function saveFile(filename, contents, callback) {
  mkdirp(path.dirname(filename), err => {
    if (err) {
      return callback(err);
    }
    fs.writeFile(filename, contents, callback);
  });
}

function download(url, filename) {
  console.log(`Downloading ${url}`);

  let body;

  return request(url)
    .then(response => {
      "use strict";
      body = response.body;
      return mkdirp(path.dirname(filename));
    })
    .then(() => writeFile(filename, body))
    .then(() => {
      "use strict";
      console.log(`Downloaded adn saved: ${url}`);
      return body;
    });
}

/// promise编程的本质就是为了解决在函数中设置回调函数的问题
/// 通过中间层promise来实现异步函数同步化
function spiderLinks(currentUrl, body, nesting) {
  let promise = Promise.resolve();
  if (nesting === 0) {
    return promise;
  }

  const links = utilities.getPageLinks(currentUrl, body);

  links.forEach(link => {
    "use strict";
    promise = promise.then(() => spider(link, nesting - 1));
  });

  return promise;
}

function spider(url, nesting) {
  const filename = utilities.urlToFilename(url);

  return readFile(filename, "utf8")
    .then(
      body => spiderLinks(url, body, nesting),
      err => {
        "use strict";
        if (err.code !== &#39;ENOENT&#39;) {
          /// 抛出错误,这个方便与在整个异步链的最后通过呢catch来捕获这个链中的错误
          throw err;
        }
        return download(url, filename)
          .then(body => spiderLinks(url, body, nesting));
      }
    );
}

spider(process.argv[2], 1)
  .then(() => {
    "use strict";
    console.log(&#39;Download complete&#39;);
  })
  .catch(err => {
    "use strict";
    console.log(err);
  });
Copier après la connexion

可以看到上边的代码中的函数都是没有callback的,只需要在最后catch就可以了。

在设计api的时候,应该支持两种方式,及支持callback,又支持promise


function asyncpision(pidend, pisor, cb) {
  return new Promise((resolve, reject) => {
    "use strict";
    process.nextTick(() => {
      const result = pidend / pisor;
      if (isNaN(result) || !Number.isFinite(result)) {
        const error = new Error("Invalid operands");
        if (cb) {
          cb(error);
        }
        return reject(error);
      }

      if (cb) {
        cb(null, result);
      }
      resolve(result);
    });
  });
}

asyncpision(10, 2, (err, result) => {
  "use strict";
  if (err) {
    return console.log(err);
  }
  console.log(result);
});

asyncpision(22, 11)
  .then((result) => console.log(result))
  .catch((err) => console.log(err));
Copier après la connexion

4.Generator

Generator很有意思,他可以让暂停函数和恢复函数,利用thunkify和co这两个库,我们下边的代码实现起来非常酷。

(spider_v9.js)


const thunkify = require("thunkify");
const co = require("co");
const path = require("path");
const utilities = require("./utilities");

const request = thunkify(require("request"));
const fs = require("fs");
const mkdirp = thunkify(require("mkdirp"));
const readFile = thunkify(fs.readFile);
const writeFile = thunkify(fs.writeFile);
const nextTick = thunkify(process.nextTick);

function* download(url, filename) {
  console.log(`Downloading ${url}`);

  const response = yield request(url);
  console.log(response);

  const body = response[1];
  yield mkdirp(path.dirname(filename));

  yield writeFile(filename, body);

  console.log(`Downloaded and saved ${url}`);
  return body;
}

function* spider(url, nesting) {
  const filename = utilities.urlToFilename(url);

  let body;

  try {
    body = yield readFile(filename, "utf8");
  } catch (err) {
    if (err.code !== &#39;ENOENT&#39;) {
      throw err;
    }
    body = yield download(url, filename);
  }

  yield spiderLinks(url, body, nesting);
}

function* spiderLinks(currentUrl, body, nesting) {
  if (nesting === 0) {
    return nextTick();
  }

  const links = utilities.getPageLinks(currentUrl, body);

  for (let i = 0; i < links.length; i++) {
    yield spider(links[i], nesting - 1);
  }
}

/// 通过co就自动处理了回调函数,直接返回了回调函数中的参数,把这些参数放到一个数组中,但是去掉了err信息
co(function* () {
  try {
    yield spider(process.argv[2], 1);
    console.log(&#39;Download complete&#39;);
  } catch (err) {
    console.log(err);
  }
});
Copier après la connexion

总结

我并没有写promise和generator并发的代码。以上这些内容来自于这本书nodejs-design-patterns 。

相关推荐:

Node.js之关于异步流控制的简单介绍

微信小程序中Promise进行异步流程处理的实现过程

小程序开发之利用co处理异步流程的实例教程

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 de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
1 Il y a quelques mois By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Explication détaillée de l'obtention des droits d'administrateur dans Win11 Explication détaillée de l'obtention des droits d'administrateur dans Win11 Mar 08, 2024 pm 03:06 PM

Le système d'exploitation Windows est l'un des systèmes d'exploitation les plus populaires au monde et sa nouvelle version Win11 a beaucoup attiré l'attention. Dans le système Win11, l'obtention des droits d'administrateur est une opération importante. Les droits d'administrateur permettent aux utilisateurs d'effectuer davantage d'opérations et de paramètres sur le système. Cet article présentera en détail comment obtenir les autorisations d'administrateur dans le système Win11 et comment gérer efficacement les autorisations. Dans le système Win11, les droits d'administrateur sont divisés en deux types : administrateur local et administrateur de domaine. Un administrateur local dispose de tous les droits d'administration sur l'ordinateur local

Explication détaillée du fonctionnement de la division dans Oracle SQL Explication détaillée du fonctionnement de la division dans Oracle SQL Mar 10, 2024 am 09:51 AM

Explication détaillée de l'opération de division dans OracleSQL Dans OracleSQL, l'opération de division est une opération mathématique courante et importante, utilisée pour calculer le résultat de la division de deux nombres. La division est souvent utilisée dans les requêtes de bases de données. Comprendre le fonctionnement de la division et son utilisation dans OracleSQL est donc l'une des compétences essentielles des développeurs de bases de données. Cet article discutera en détail des connaissances pertinentes sur les opérations de division dans OracleSQL et fournira des exemples de code spécifiques pour référence aux lecteurs. 1. Opération de division dans OracleSQL

Explication détaillée du rôle et de l'utilisation de l'opérateur modulo PHP Explication détaillée du rôle et de l'utilisation de l'opérateur modulo PHP Mar 19, 2024 pm 04:33 PM

L'opérateur modulo (%) en PHP est utilisé pour obtenir le reste de la division de deux nombres. Dans cet article, nous discuterons en détail du rôle et de l'utilisation de l'opérateur modulo et fournirons des exemples de code spécifiques pour aider les lecteurs à mieux comprendre. 1. Le rôle de l'opérateur modulo En mathématiques, lorsqu'on divise un entier par un autre entier, on obtient un quotient et un reste. Par exemple, lorsque l’on divise 10 par 3, le quotient est 3 et le reste est 1. L'opérateur modulo est utilisé pour obtenir ce reste. 2. Utilisation de l'opérateur modulo En PHP, utilisez le symbole % pour représenter le module

Explication détaillée de la fonction d'appel système Linux system() Explication détaillée de la fonction d'appel système Linux system() Feb 22, 2024 pm 08:21 PM

Explication détaillée de la fonction d'appel système Linux system() L'appel système est une partie très importante du système d'exploitation Linux. Il fournit un moyen d'interagir avec le noyau système. Parmi elles, la fonction system() est l’une des fonctions d’appel système couramment utilisées. Cet article présentera en détail l’utilisation de la fonction system() et fournira des exemples de code correspondants. Concepts de base des appels système Les appels système sont un moyen permettant aux programmes utilisateur d'interagir avec le noyau du système d'exploitation. Les programmes utilisateur demandent au système d'exploitation en appelant des fonctions d'appel système

Explication détaillée de la commande Linux curl Explication détaillée de la commande Linux curl Feb 21, 2024 pm 10:33 PM

Explication détaillée de la commande curl de Linux Résumé : curl est un puissant outil de ligne de commande utilisé pour la communication de données avec le serveur. Cet article présentera l'utilisation de base de la commande curl et fournira des exemples de code réels pour aider les lecteurs à mieux comprendre et appliquer la commande. 1. Qu’est-ce que la boucle ? curl est un outil de ligne de commande utilisé pour envoyer et recevoir diverses requêtes réseau. Il prend en charge plusieurs protocoles, tels que HTTP, FTP, TELNET, etc., et fournit des fonctions riches, telles que le téléchargement de fichiers, le téléchargement de fichiers, la transmission de données, le proxy.

Tutoriel JavaScript simple : Comment obtenir le code d'état HTTP Tutoriel JavaScript simple : Comment obtenir le code d'état HTTP Jan 05, 2024 pm 06:08 PM

Tutoriel JavaScript : Comment obtenir le code d'état HTTP, des exemples de code spécifiques sont requis Préface : Dans le développement Web, l'interaction des données avec le serveur est souvent impliquée. Lors de la communication avec le serveur, nous devons souvent obtenir le code d'état HTTP renvoyé pour déterminer si l'opération a réussi et effectuer le traitement correspondant en fonction de différents codes d'état. Cet article vous apprendra comment utiliser JavaScript pour obtenir des codes d'état HTTP et fournira quelques exemples de codes pratiques. Utilisation de XMLHttpRequest

Analyse détaillée du parcours d'apprentissage du langage C Analyse détaillée du parcours d'apprentissage du langage C Feb 18, 2024 am 10:38 AM

En tant que langage de programmation largement utilisé dans le domaine du développement de logiciels, le langage C est le premier choix de nombreux programmeurs débutants. L'apprentissage du langage C peut non seulement nous aider à acquérir des connaissances de base en programmation, mais également à améliorer nos capacités de résolution de problèmes et de réflexion. Cet article présentera en détail une feuille de route d'apprentissage du langage C pour aider les débutants à mieux planifier leur processus d'apprentissage. 1. Apprendre la grammaire de base Avant de commencer à apprendre le langage C, nous devons d'abord comprendre les règles de grammaire de base du langage C. Cela inclut les variables et les types de données, les opérateurs, les instructions de contrôle (telles que les instructions if,

En savoir plus sur Promise.resolve() En savoir plus sur Promise.resolve() Feb 18, 2024 pm 07:13 PM

Une explication détaillée de Promise.resolve() nécessite des exemples de code spécifiques. Promise est un mécanisme en JavaScript pour gérer les opérations asynchrones. Dans le développement réel, il est souvent nécessaire de traiter certaines tâches asynchrones qui doivent être exécutées dans l'ordre, et la méthode Promise.resolve() est utilisée pour renvoyer un objet Promise qui a été rempli. Promise.resolve() est une méthode statique de la classe Promise, qui accepte un

See all articles