मेरे पास Array.forEach
जावास्क्रिप्ट के मूल कार्यान्वयन के बारे में एक प्रश्न है : क्या यह अतुल्यकालिक व्यवहार करता है? उदाहरण के लिए, यदि मैं फोन करता हूं:
[many many elements].forEach(function () {lots of work to do})
क्या यह गैर-अवरुद्ध होगा?
मेरे पास Array.forEach
जावास्क्रिप्ट के मूल कार्यान्वयन के बारे में एक प्रश्न है : क्या यह अतुल्यकालिक व्यवहार करता है? उदाहरण के लिए, यदि मैं फोन करता हूं:
[many many elements].forEach(function () {lots of work to do})
क्या यह गैर-अवरुद्ध होगा?
जवाबों:
नहीं, यह अवरुद्ध है। एल्गोरिथ्म के विनिर्देश पर एक नज़र है ।
हालाँकि MDN पर कार्यान्वयन को समझना आसान है :
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisp */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisp, t[i], i, t);
}
};
}
यदि आपको प्रत्येक तत्व के लिए बहुत सारे कोड निष्पादित करने हैं, तो आपको एक अलग दृष्टिकोण का उपयोग करने पर विचार करना चाहिए:
function processArray(items, process) {
var todo = items.concat();
setTimeout(function() {
process(todo.shift());
if(todo.length > 0) {
setTimeout(arguments.callee, 25);
}
}, 25);
}
और फिर इसके साथ कॉल करें:
processArray([many many elements], function () {lots of work to do});
यह तब गैर-अवरुद्ध होगा। इसका उदाहरण उच्च प्रदर्शन जावास्क्रिप्ट से लिया गया है ।
एक अन्य विकल्प वेब कर्मचारी हो सकता है ।
forEach
करता है और आपको लूप का उपयोग करना चाहिए : stackoverflow.com/questions/37962880/…await
for
await
अंदर के async
कार्यों का उपयोग कर सकते हैं । लेकिन forEach
पता नहीं है कि async फ़ंक्शन क्या हैं। ध्यान रखें कि async फ़ंक्शन केवल वादे वापस करने वाले फ़ंक्शंस हैं। क्या आप forEach
कॉलबैक से लौटे एक वादे को संभालने की उम्मीद करेंगे ? forEach
कॉलबैक से वापसी मूल्य को पूरी तरह से अनदेखा करता है। यह केवल एक async कॉलबैक को संभालने में सक्षम होगा यदि यह स्वयं async था।
यदि आपको एसिंक्रोनस-फ्रेंडली संस्करण की आवश्यकता है Array.forEach
, तो वे Node.js 'async' मॉड्यूल में उपलब्ध हैं: http://github.com/caolan/async ... एक बोनस के रूप में यह मॉड्यूल ब्राउज़र में भी काम करता है ।
async.each(openFiles, saveFile, function(err){
// if any of the saves produced an error, err would equal that error
});
eachSeries
इसके बजाय उपयोग करना होगा ।
नोड में वास्तव में भारी गणना करने के लिए एक सामान्य पैटर्न है जो आपके लिए लागू हो सकता है ...
नोड सिंगल-थ्रेडेड है (एक जानबूझकर डिजाइन विकल्प के रूप में, देखें कि Node.js क्या है? ); इसका मतलब है कि यह केवल एक कोर का उपयोग कर सकता है। आधुनिक बक्सों में 8, 16 या अधिक कोर हैं, इसलिए यह मशीन के 90%% को निष्क्रिय कर सकता है। एक REST सेवा के लिए सामान्य पैटर्न प्रति नोड एक नोड प्रक्रिया को फायर करना है, और इनको http://nginx.org/ जैसे स्थानीय लोड बैलेंसर के पीछे रखना है ।
एक बच्चे के लिए धन्यवाद - आप जो करने की कोशिश कर रहे हैं, उसके लिए एक और सामान्य पैटर्न है, भारी उठाने के लिए एक बच्चे की प्रक्रिया को बंद करना। उल्टा यह है कि बच्चे की प्रक्रिया पृष्ठभूमि में भारी गणना कर सकती है, जबकि आपकी मूल प्रक्रिया अन्य घटनाओं के लिए उत्तरदायी है। पकड़ यह है कि आप इस बच्चे की प्रक्रिया के साथ स्मृति को साझा नहीं कर सकते हैं / नहीं करना चाहिए (गर्भनिरोधक और कुछ देशी कोड के बिना नहीं); आपको संदेश पास करना होगा। यह खूबसूरती से काम करेगा यदि आपके इनपुट और आउटपुट डेटा का आकार उस संगणना की तुलना में छोटा है जिसे निष्पादित किया जाना चाहिए। तुम भी एक बच्चे नोड .js प्रक्रिया को आग लगा सकते हैं और उसी कोड का उपयोग कर सकते हैं जो आप पहले उपयोग कर रहे थे।
उदाहरण के लिए:
var child_process = आवश्यकता ('child_process'); समारोह run_in_child (सरणी, cb) { var प्रक्रिया = child_process.exec ('नोड libfn.js', फंक्शन (इरेट, स्टडआउट, स्टैडर) { var आउटपुट = JSON.parse (stdout); सीबी (इरेट, आउटपुट); }); process.stdin.write (JSON.stringify (सरणी), 'utf8'); process.stdin.end (); }
Array.forEach
अभिकलन सामान की प्रतीक्षा नहीं करने के लिए है, और एक ईवेंट लूप में अतुल्यकालिक बनाने के लिए कुछ भी प्राप्त नहीं किया जा सकता है (यदि आपके पास मल्टी-कोर कम्प्यूटेशन की आवश्यकता है, तो वेबवर्क मल्टीप्रोसेसिंग जोड़ते हैं)। यदि आप कई कार्यों को समाप्त करने के लिए इंतजार करना चाहते हैं, तो एक काउंटर का उपयोग करें, जिसे आप एक अर्ध-श्रेणी में लपेट सकते हैं।
2018-10-11 को संपादित करें: ऐसा लगता है कि एक अच्छा मौका है जो नीचे वर्णित मानक के माध्यम से नहीं जा सकता है, एक विकल्प के रूप में पाइपलाइनिंग पर विचार करें (बिल्कुल वैसा ही व्यवहार नहीं करता है लेकिन एक समान जागीर में तरीकों को लागू किया जा सकता है)।
यह ठीक यही है कि मैं es7 के बारे में उत्साहित हूं, भविष्य में आप नीचे दिए गए कोड की तरह कुछ कर पाएंगे (कुछ चश्मा पूरा नहीं है इसलिए सावधानी के साथ उपयोग करें, मैं इसे अद्यतित रखने की कोशिश करूंगा)। लेकिन मूल रूप से नए :: bind ऑपरेटर का उपयोग करते हुए, आप किसी ऑब्जेक्ट पर एक विधि चलाने में सक्षम होंगे जैसे कि ऑब्जेक्ट के प्रोटोटाइप में विधि होती है। उदाहरण [वस्तु] :: [विधि] जहां आम तौर पर आप [वस्तु] कहते हैं। [ObjectsMethod]
आज (24-जुलाई -16) ऐसा करने के लिए ध्यान दें और यह सभी ब्राउज़रों में काम करता है, आपको निम्न कार्यक्षमता के लिए अपने कोड को ट्रांसपाइल करना होगा: आयात / निर्यात , एरो फ़ंक्शंस , वादे , Async / Await और सबसे महत्वपूर्ण रूप से फ़ंक्शन बाइंड । नीचे दिए गए कोड को केवल फ़ंक्शन बाइंड का उपयोग करने के लिए संशोधित किया जा सकता है यदि नेस्सेरी, यह सब कार्यक्षमता बबेल का उपयोग करके आज बड़े करीने से उपलब्ध है ।
YourCode.js (जहां ' बहुत सारे काम करने के लिए ' बस एक वादा वापस करना होगा, इसे हल करना जब अतुल्यकालिक काम पूरा हो जाएगा।)
import { asyncForEach } from './ArrayExtensions.js';
await [many many elements]::asyncForEach(() => lots of work to do);
ArrayExtensions.js
export function asyncForEach(callback)
{
return Promise.resolve(this).then(async (ar) =>
{
for(let i=0;i<ar.length;i++)
{
await callback.call(ar, ar[i], i, ar);
}
});
};
export function asyncMap(callback)
{
return Promise.resolve(this).then(async (ar) =>
{
const out = [];
for(let i=0;i<ar.length;i++)
{
out[i] = await callback.call(ar, ar[i], i, ar);
}
return out;
});
};
यह थर्ड पार्टी लिबास की आवश्यकता के बिना उपयोग करने के लिए एक छोटा एसिंक्रोनस फ़ंक्शन है
Array.prototype.each = function (iterator, callback) {
var iterate = function () {
pointer++;
if (pointer >= this.length) {
callback();
return;
}
iterator.call(iterator, this[pointer], iterate, pointer);
}.bind(this),
pointer = -1;
iterate(this);
};
प्रत्येक लूप के लिए आसान अतुल्यकालिक के लिए npm पर एक पैकेज है ।
var forEachAsync = require('futures').forEachAsync;
// waits for one request to finish before beginning the next
forEachAsync(['dogs', 'cats', 'octocats'], function (next, element, index, array) {
getPics(element, next);
// then after all of the elements have been handled
// the final callback fires to let you know it's all done
}).then(function () {
console.log('All requests have finished');
});
इसके अलावा एक और बदलाव forAllAsync
उदाहरण के लिए इस तरह के समाधान को भी कोड करना संभव है:
var loop = function(i, data, callback) {
if (i < data.length) {
//TODO("SELECT * FROM stackoverflowUsers;", function(res) {
//data[i].meta = res;
console.log(i, data[i].title);
return loop(i+1, data, errors, callback);
//});
} else {
return callback(data);
}
};
loop(0, [{"title": "hello"}, {"title": "world"}], function(data) {
console.log("DONE\n"+data);
});
दूसरी ओर, यह "के लिए" की तुलना में बहुत धीमा है।
अन्यथा, उत्कृष्ट Async लाइब्रेरी यह कर सकती है: https://caolan.github.io/async/docs.html#each
यहाँ एक छोटा सा उदाहरण है जिसे आप इसका परीक्षण करने के लिए चला सकते हैं:
[1,2,3,4,5,6,7,8,9].forEach(function(n){
var sum = 0;
console.log('Start for:' + n);
for (var i = 0; i < ( 10 - n) * 100000000; i++)
sum++;
console.log('Ended for:' + n, sum);
});
यह कुछ इस तरह का उत्पादन करेगा (यदि इसमें बहुत कम / बहुत समय लगता है, पुनरावृत्तियों की संख्या में वृद्धि / कमी करें):
(index):48 Start for:1
(index):52 Ended for:1 900000000
(index):48 Start for:2
(index):52 Ended for:2 800000000
(index):48 Start for:3
(index):52 Ended for:3 700000000
(index):48 Start for:4
(index):52 Ended for:4 600000000
(index):48 Start for:5
(index):52 Ended for:5 500000000
(index):48 Start for:6
(index):52 Ended for:6 400000000
(index):48 Start for:7
(index):52 Ended for:7 300000000
(index):48 Start for:8
(index):52 Ended for:8 200000000
(index):48 Start for:9
(index):52 Ended for:9 100000000
(index):45 [Violation] 'load' handler took 7285ms
Bluebird लाइब्रेरी के Promise.each का उपयोग करें ।
Promise.each(
Iterable<any>|Promise<Iterable<any>> input,
function(any item, int index, int length) iterator
) -> Promise
यह विधि किसी सरणी, या किसी वादे के वादे पर निर्भर करती है, जिसमें हस्ताक्षर (मूल्य, सूचकांक, लंबाई) के साथ दिए गए पुनरावृत्ति फ़ंक्शन के साथ वादे (या वादों और मूल्यों का मिश्रण ) शामिल हैं, जहां मूल्य का हल मूल्य है इनपुट एरे में संबंधित वादा। क्रमबद्धता से होता है। यदि पुनरावृत्ति फ़ंक्शन एक वादा या एक उल्लेखनीय रिटर्न देता है, तो अगले पुनरावृत्ति जारी रखने से पहले वादे के परिणाम का इंतजार किया जाता है। यदि इनपुट ऐरे में कोई वादा अस्वीकार कर दिया जाता है, तो वापस किया गया वादा भी अस्वीकार कर दिया जाता है।
यदि सभी पुनरावृत्तियां सफलतापूर्वक हल हो जाती हैं, तो Promise.each मूल सरणी को निराधार रूप से हल करता है । हालाँकि, यदि कोई पुनरावृति अस्वीकार या त्रुटियां करता है, Promise.each तुरंत निष्पादन को समाप्त कर देता है और आगे पुनरावृत्तियों को संसाधित नहीं करता है। मूल सरणी के बजाय इस मामले में त्रुटि या अस्वीकृत मान लौटाया जाता है।
इस विधि का उपयोग साइड इफेक्ट के लिए किया जाता है।
var fileNames = ["1.txt", "2.txt", "3.txt"];
Promise.each(fileNames, function(fileName) {
return fs.readFileAsync(fileName).then(function(val){
// do stuff with 'val' here.
});
}).then(function() {
console.log("done");
});