Yanıtlar:
Hayır, engelliyor. Algoritmanın özelliklerine bir göz atın .
Ancak MDN'de anlaşılması belki daha kolay bir uygulamadır :
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);
}
};
}
Her öğe için çok sayıda kod yürütmeniz gerekiyorsa, farklı bir yaklaşım kullanmayı düşünmelisiniz:
function processArray(items, process) {
var todo = items.concat();
setTimeout(function() {
process(todo.shift());
if(todo.length > 0) {
setTimeout(arguments.callee, 25);
}
}, 25);
}
ve şununla ara:
processArray([many many elements], function () {lots of work to do});
O zaman bu engellemeyecekti. Örnek Yüksek Performanslı JavaScript'ten alınmıştır .
Başka bir seçenek web çalışanları olabilir .
forEach
yok değil engelle await
örneğin tablolar ve yerine bir kullanmalıdır for
döngü: stackoverflow.com/questions/37962880/...
await
iç async
işlevleri kullanabilirsiniz . Ancak forEach
asenkron fonksiyonların ne olduğunu bilmiyor. Zaman uyumsuz işlevlerin yalnızca bir söz veren işlevler olduğunu unutmayın. forEach
Geri aramadan iade edilen bir sözü yerine getirmeyi bekler misiniz ? forEach
Geri aramadaki dönüş değerini tamamen yok sayar. Bir eşzamansız geri çağrıyı yalnızca eşzamansız kendisi olsaydı işleyebilirdi.
Eşzamanlı olmayan bir sürümüne Array.forEach
ve benzeri bir sürüme ihtiyacınız varsa , Node.js 'eşzamansız' modülünde mevcuttur: http://github.com/caolan/async ... bonus olarak bu modül tarayıcıda da çalışır .
async.each(openFiles, saveFile, function(err){
// if any of the saves produced an error, err would equal that error
});
eachSeries
bunun yerine kullanmanız gerekir .
Düğümde sizin için geçerli olabilecek gerçekten ağır bir hesaplama yapmak için yaygın bir kalıp vardır ...
Düğüm tek iş parçacıklı (kasıtlı bir tasarım seçeneği olarak bkz. Node.js nedir? ); bu sadece tek bir çekirdeği kullanabileceği anlamına gelir. Modern kutular 8, 16 veya daha fazla çekirdeğe sahiptir, bu da makinenin% 90 + 'sını boşta bırakabilir. Bir REST hizmeti için ortak model, çekirdek başına bir düğüm işlemi başlatmak ve bunları http://nginx.org/ gibi yerel bir yük dengeleyicisinin arkasına koymaktır .
Bir çocuğu çatallamak - Yapmaya çalıştığınız şey için, ağır kaldırmayı yapmak için bir çocuk sürecini çürüten başka bir ortak desen var. Bunun üst tarafı, ana süreciniz diğer olaylara yanıt verirken alt sürecin arka planda ağır hesaplama yapabilmesidir. Yakalama, bu alt süreçle hafızayı paylaşamayacağınız / paylaşamamanızdır (çok fazla eğri ve bazı yerel kodlar olmadan değil); mesajları iletmeniz gerekiyor. Giriş ve çıkış verilerinizin boyutu, gerçekleştirilmesi gereken hesaplamaya kıyasla küçükse, güzel bir şekilde çalışacaktır. Bir alt node.js işlemini bile başlatabilir ve daha önce kullandığınız kodun aynısını kullanabilirsiniz.
Örneğin:
var child_process = requir ('child_process'); işlev run_in_child (dizi, cb) { var process = child_process.exec ('düğüm libfn.js', işlev (err, stdout, stderr) { var output = JSON.parse (stdout); cb (hata, çıktı); }); process.stdin.write (JSON.stringify (dizi), 'utf8'); ) (Process.stdin.end; }
Array.forEach
beklemeyen şeyleri hesaplamak içindir ve bir olay döngüsünde hesaplamaları eşzamansız hale getirmek için kazanılacak hiçbir şey yoktur (çok çekirdekli hesaplamaya ihtiyacınız varsa web işçileri çoklu işlem ekler). Birden fazla görevin bitmesini beklemek istiyorsanız, bir semafor sınıfına sarılabileceğiniz bir sayaç kullanın.
Edit 2018-10-11: Aşağıda açıklanan standardın geçemeyebileceği iyi bir şans var gibi görünüyor, boru hattını alternatif olarak düşünün (tam olarak aynı davranmıyor, ancak benzer bir malikanede yöntemler uygulanabilir).
Bu yüzden es7 hakkında heyecanlıyım, gelecekte aşağıdaki kod gibi bir şey yapabileceksiniz (bazı özellikler tam değildir, bu yüzden dikkatli kullanın, bunu güncel tutmaya çalışacağım). Ancak temel olarak new :: bind işlecini kullanarak, nesnenin prototipi yöntemi içeriyormuş gibi bir nesne üzerinde yöntem çalıştırabilirsiniz. örneğin [Object] :: [Yöntem] burada normalde [Object] olarak adlandırırsınız. [ObjectsMethod]
Bunu bugün (24-Temmuz-16) yapmak ve tüm tarayıcılarda çalışmasını sağlamak için aşağıdaki işlevler için kodunuzu aktarmanız gerekir: İçe / Dışa Aktar , Ok işlevleri , Vaatler , Async / Bekle ve en önemlisi işlev bağlama . Aşağıdaki kod, yalnızca gerekli olduğunda bağlama işlevini kullanacak şekilde değiştirilebilir, tüm bu işlevler bugün babel kullanılarak düzgün bir şekilde kullanılabilir .
YourCode.js ('yapılacak çok iş ' basitçe bir söz vermeli ve eşzamansız iş yapıldığında çözülmelidir.)
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;
});
};
Bu, üçüncü taraf kütüphanelerine ihtiyaç duymadan kullanılacak kısa bir asenkron işlevdir
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);
};
Her döngü için kolay eşzamansız npm'de bir paket var .
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');
});
AllAsync için başka bir varyasyon
Böyle bir çözümü bile kodlamak mümkündür, örneğin:
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);
});
Öte yandan, bir "for" dan çok daha yavaştır.
Aksi takdirde, mükemmel Async kütüphanesi bunu yapabilir: https://caolan.github.io/async/docs.html#each
Test etmek için çalıştırabileceğiniz küçük bir örnek:
[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);
});
Böyle bir şey üretecektir (çok daha az / çok zaman alırsa, yineleme sayısını artırın / azaltın):
(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
Kullanım Promise.each ait bluebird kütüphanesine.
Promise.each(
Iterable<any>|Promise<Iterable<any>> input,
function(any item, int index, int length) iterator
) -> Promise
Verilen bir dizi ya da söz içeren bir dizi (ya da söz ve değerlerin bir karışımı) bir söz üzerinde Bu yöntem dolaşır yineleyici imza ile fonksiyonu (değer, dizin, uzunluk) değeri a'nın çözülmesi değerdir giriş dizisindeki ilgili vaat. Yineleme seri olarak gerçekleşir. Yineleyici işlevi bir söz veya ötelenebilir değer döndürürse, söz konusu sonucun bir sonraki yinelemeye devam etmeden önce beklenmesi gerekir. Girdi dizisindeki herhangi bir vaat reddedilirse, döndürülen vaat de reddedilir.
Tüm yinelemeler başarıyla çözülürse , Promise.each değiştirilmemiş orijinal diziye gider . Ancak, bir yineleme reddedilirse veya hata verirse , Promise.each hemen yürütmeyi durdurur ve başka yinelemeleri işlemez. Bu durumda, orijinal dizi yerine hata veya reddedilen değer döndürülür.
Bu yöntemin yan etkiler için kullanılması amaçlanmıştır.
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");
});