Heim >Web-Frontend >js-Tutorial >Detaillierte Erläuterung der Verwendung von Async in Javascript
In diesem Artikel wird hauptsächlich die Verwendung von Javascript Async vorgestellt. Der Herausgeber findet es ziemlich gut. Jetzt werde ich es mit Ihnen teilen und es als Referenz geben. Folgen wir dem Editor und werfen wir einen Blick darauf.
Vorab geschrieben
In diesem Artikel wird eine optimale Methode zum sequentiellen Lesen von Dateien implementiert. Die Implementierungsmethode beginnt mit Die älteste Rückrufmethode für die aktuelle Async-Methode. Ich werde Ihnen auch mein Verständnis der Thunk-Bibliothek und der Co-Bibliothek mitteilen. Der erzielte Effekt: Lesen Sie a.txt und b.txt nacheinander und verketten Sie den gelesenen Inhalt zu einer Zeichenfolge.
Synchronisiertes Lesen
const readTwoFile = () => { const f1 = fs.readFileSync('./a.txt'), f2 = fs.readFileSync('./b.txt'); return Buffer.concat([f1, f2]).toString(); };
Diese Methode ist für unser Verständnis am förderlichsten, und der Code ist sehr gut Klar, nein Zu viel Verschachtelung, gute Wartung, aber das hat das größte Problem, nämlich die Leistung. Was der Knoten befürwortet, ist asynchrone E/A, um intensive E/A zu bewältigen, und synchrones Lesen ist größtenteils eine Verschwendung Die Nachteile dieser Methode überwiegen offensichtlich die Vorteile, also lassen Sie sie einfach bestehen. (Tatsächlich besteht das Ziel jeder asynchronen Programmierlösung im Knoten darin, synchrone Semantik und asynchrone Ausführung zu erreichen.)
Verwenden Sie Rückrufe zum Lesen
const readTwoFile = () => { let str = null; fs.readFile('./a.txt', (err, data) => { if (err) throw new Error(err); str = data; fs.readFile('./b.txt', (err, data) => { if (err) throw new Error(err); str = Buffer.concat([str, data]).toString(); }); }); };
Mit der Rückrufmethode ist es sehr einfach, sie direkt zu verschachteln. In diesem Fall kann es jedoch leicht zu einer Situation kommen, die schwer zu warten und schwer zu verstehen ist. Die Extremsituation ist die Callback-Hölle.
Promise-Implementierung
const readFile = file => new Promise((reslove, reject) => { fs.readFile(file, (err, data) => { if (err) reject(err); reslove(data); }); }); const readTwoFile = () => { let bf = null; readFile('./a.txt') .then( data => { bf = data; return readFile('./b.txt'); }, err => { throw new Error(err) } ) .then( data => { console.log(Buffer.concat([bf, data]).toString()) }, err => { throw new Error(err) } ); };
Promise kann horizontale Wachstumsrückrufe in vertikales Wachstum umwandeln, was einige Probleme lösen kann Das Problem, aber das durch Promise verursachte Problem ist die Code-Redundanz. Auf den ersten Blick ist das alles nicht sehr komfortabel, aber im Vergleich zur Verschachtelung von Rückruffunktionen wurde es erheblich verbessert.
Yield
Generator ist in vielen Sprachen verfügbar. Es handelt sich im Wesentlichen um eine Coroutine :
Prozess: Die Grundeinheit der Ressourcenzuweisung im Betriebssystem
Thread: Die Grundeinheit der Ressourcenplanung im Betriebssystem
Coroutine: eine Ausführungseinheit, die kleiner als ein Thread ist, mit eigenem CPU-Kontext, einer Coroutine und einem Stack
Es können mehrere Threads vorhanden sein In einem Prozess können mehrere Coroutinen vorhanden sein. Der Wechsel von Prozessen und Threads wird vom Betriebssystem gesteuert, während der Wechsel von Coroutinen vom Programmierer selbst gesteuert wird. Asynchrone E/A verwendet Rückrufe, um intensive E/A-Vorgänge zu bewältigen. Das Wechseln von Coroutinen verschwendet nicht viele Ressourcen. Schreiben Sie einen E/A-Vorgang in eine Coroutine und gehen Sie so vor. O, Sie können die CPU an andere Coroutinen abgeben.
js unterstützt auch Coroutinen, was Yield ist. Das intuitive Gefühl, das uns die Verwendung von yield vermittelt, ist, dass die Ausführung an dieser Stelle stoppt und anderer Code weiter ausgeführt wird. Wenn Sie möchten, dass die Ausführung fortgesetzt wird, wird er auch weiterhin ausgeführt.
function *readTwoFile() { const f1 = yield readFile('./a.txt'); const f2 = yield readFile('./b.txt'); return Buffer.concat([f1, f2]).toString(); }
Sequentielles Lesen unter yield stellt auch eine sequentielle Lesemethode dar. Es gibt zwei verschiedene Implementierungsmethoden für readFile:
Verwenden Sie thunkify
const thunkify = (fn, ctx) => (...items) => (done) => { ctx = ctx || null; let called = false; items.push((...args) => { if (called) return void 0; called = true; done.apply(ctx, args); }); try { fn.apply(ctx, items); } catch(err) { done(err); } };
Die Thunkify-Funktion ist eine Art Curry-Idee. Der letzte eingehende Parameter ist die Callback-Funktion. Der automatisierte Prozess der Yield-Funktion kann einfach implementiert werden :
const run = fn => { const gen = fn(); let res; (function next(err, data) { let g = gen.next(data); if (g.done) return void 0; g.value(next); })(); };
Use Promise
const readFile = file => new Promise((reslove, reject) => { fs.readFile(file, (err, data) => { if (err) reject(err); reslove(data); }); }); const run = fn => { const gen = fn(); let str = null; (function next(err, data) { let res = gen.next(data); if (res.done) return void 0; res.value.then( data => { next(null, data); }, err => { throw new Error(err); } ); })(); }; run(readTwoFile);
Beide der beiden oben genannten Methoden können erreicht werden Gibt es eine Möglichkeit, die mit diesen beiden Implementierungsmethoden kompatibel ist, nämlich die Co-Bibliothek?
// readTwoFile的实现与上面类似,readFile既可以利用Promise也可以利用thunkify // co库返回一个Promise对象 co(readTwoFile).then(data => console.log(data));
const baseHandle = handle => res => { let ret; try { ret = gen[handle](res); } catch(e) { reject(e); } next(ret); }; function co(gen) { const ctx = this, args = Array.prototype.slice.call(arguments, 1); return new Promise((reslove, reject) => { if (typeof gen === 'function') gen = gen.apply(ctx, args); if (!gen || typeof gen.next !== 'function') return resolve(gen); const onFulfilled = baseHandle('next'), onRejected = baseHandle('throw'); onFulfilled(); function next(ret) { if (ret.done) reslove(ret.value); // 将yield的返回值转换为Proimse const value = toPromise.call(ctx, ret.value); if (value && isPromise(value)) return value.then(onFulfilled, onRejected); return onRejected(new TypeError('yield type error')); } }); }
// 把thunkify之后的函数转化为Promise的形式 function thunkToPromise(fn) { const ctx = this; return new Promise(function (resolve, reject) { fn.call(ctx, function (err, res) { if (err) return reject(err); if (arguments.length > 2) res = slice.call(arguments, 1); resolve(res); }); }); }Ultimative Lösung
const readFile = file => new Promise((reslove, reject) => { fs.readFile(file, (err, data) => { if (err) reject(err); reslove(data); }); }); const readTwoFile = async function() { const f1 = await readFile('./a.txt'); const f2 = await readFile('./b.txt'); return Buffer.concat([f1, f2]).toString(); }; readTwoFile().then(data => { console.log(data); });
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Verwendung von Async in Javascript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!