Tôi muốn làm rõ điểm này, vì tài liệu không quá rõ ràng về nó;
Q1: Được Promise.all(iterable)
xử lý tất cả những lời hứa tuần tự hoặc song song? Hay cụ thể hơn, nó tương đương với việc chạy các lời hứa theo chuỗi như
p1.then(p2).then(p3).then(p4).then(p5)....
hoặc là nó một số loại khác của thuật toán mà tất cả p1
, p2
, p3
, p4
, p5
, vv được gọi cùng một lúc (song song) và kết quả được trả về càng sớm càng tất cả quyết tâm (hoặc một Rejects)?
Câu hỏi 2: Nếu Promise.all
chạy song song, có cách nào thuận tiện để chạy tuần tự lặp lại không?
Lưu ý : Tôi không muốn sử dụng Q hoặc Bluebird, nhưng tất cả các thông số kỹ thuật ES6 bản địa.
Có
Promise.all(iterable)
thực hiện mọi lời hứa không?
Không, lời hứa không thể "được thực hiện". Chúng bắt đầu tác vụ khi chúng đang được tạo - chúng chỉ đại diện cho kết quả - và bạn đang thực hiện mọi thứ song song ngay cả trước khi chuyển chúng đến Promise.all
.
Promise.all
chỉ chờ đợi nhiều lời hứa. Nó không quan tâm đến thứ tự chúng giải quyết, hoặc liệu các tính toán có chạy song song hay không.
có cách nào thuận tiện để chạy tuần tự có thể lặp lại không?
Nếu bạn đã có những lời hứa của mình, bạn không thể làm được gì nhiều ngoài việc Promise.all([p1, p2, p3, …])
(không có khái niệm về trình tự). Nhưng nếu bạn có một hàm không đồng bộ có thể lặp lại, bạn thực sự có thể chạy chúng tuần tự. Về cơ bản, bạn cần nhận được từ
[fn1, fn2, fn3, …]
đến
fn1().then(fn2).then(fn3).then(…)
và giải pháp để làm điều đó là sử dụng Array::reduce
:
iterable.reduce((p, fn) => p.then(fn), Promise.resolve())
await Promise.all(items.map(async item => { await fetchItem(item) }))
Ưu điểm: Nhanh hơn. Tất cả các lần lặp sẽ được bắt đầu ngay cả khi không thành công.
for (let i = 0; i < items.length; i++) {
await fetchItem(items[i])
}
Ưu điểm: Các biến trong vòng lặp có thể được chia sẻ theo từng lần lặp. Hoạt động giống như mã đồng bộ mệnh lệnh bình thường.
Câu trả lời của Bergis đã giúp tôi đi đúng hướng khi sử dụng Array.reduce.
Tuy nhiên, để thực sự nhận được các hàm trả về các lời hứa của tôi để thực hiện lần lượt, tôi phải thêm một số lồng ghép nữa.
Trường hợp sử dụng thực sự của tôi là một mảng các tệp mà tôi cần chuyển theo thứ tự lần lượt do các giới hạn ở hạ lưu ...
Đây là những gì tôi đã kết thúc với.
getAllFiles().then( (files) => {
return files.reduce((p, theFile) => {
return p.then(() => {
return transferFile(theFile); //function returns a promise
});
}, Promise.resolve()).then(()=>{
console.log("All files transferred");
});
}).catch((error)=>{
console.log(error);
});
Như các câu trả lời trước gợi ý, sử dụng:
getAllFiles().then( (files) => {
return files.reduce((p, theFile) => {
return p.then(transferFile(theFile));
}, Promise.resolve()).then(()=>{
console.log("All files transferred");
});
}).catch((error)=>{
console.log(error);
});
đã không đợi quá trình chuyển hoàn tất trước khi bắt đầu một quá trình khác và văn bản "Tất cả các tệp đã được chuyển" cũng xuất hiện trước khi quá trình chuyển tệp đầu tiên được bắt đầu.
Tôi không chắc mình đã làm gì sai, nhưng muốn chia sẻ những gì có ích cho tôi.
Chỉnh sửa: Kể từ khi tôi viết bài đăng này, bây giờ tôi đã hiểu tại sao phiên bản đầu tiên không hoạt động. then () mong đợi một hàm trả về một lời hứa. Vì vậy, bạn nên chuyển vào tên hàm mà không có dấu ngoặc đơn! Bây giờ, hàm của tôi muốn một đối số, vì vậy tôi cần phải bọc trong một hàm ẩn danh không lấy đối số!
NodeJS không chạy các lời hứa song song, nó chạy chúng đồng thời vì nó là một kiến trúc vòng lặp sự kiện một luồng. Có khả năng chạy mọi thứ song song bằng cách tạo một tiến trình con mới để tận dụng lợi thế của CPU đa lõi.
Trên thực tế, những gì Promise.all
thực hiện là, xếp chồng hàm Promise vào hàng đợi thích hợp (xem kiến trúc vòng lặp sự kiện) chạy chúng đồng thời (gọi P1, P2, ...) sau đó chờ từng kết quả, sau đó giải quyết Promise.all với tất cả các hứa hẹn các kết quả. Promise.all sẽ thất bại ở lần thất bại đầu tiên, trừ khi bạn đã tự mình quản lý việc từ chối.
Có một sự khác biệt lớn giữa song song và đồng thời, cái đầu tiên sẽ chạy tính toán khác nhau trong quá trình riêng biệt vào chính xác cùng một lúc và chúng sẽ tiến triển ở đó rythme, trong khi cái kia sẽ lần lượt thực hiện các phép tính khác nhau mà không cần chờ lần trước. tính toán để hoàn thành và tiến bộ cùng một lúc mà không phụ thuộc vào nhau.
Cuối cùng, để trả lời câu hỏi của bạn, Promise.all
sẽ không thực hiện song song hoặc tuần tự mà đồng thời.
chỉ để giải thích thêm về câu trả lời của @ Bergi (rất ngắn gọn, nhưng khó hiểu;)
Mã này sẽ chạy từng mục trong mảng và thêm 'sau đó chuỗi' tiếp theo vào cuối;
function eachorder(prev,order) {
return prev.then(function() {
return get_order(order)
.then(check_order)
.then(update_order);
});
}
orderArray.reduce(eachorder,Promise.resolve());
hy vọng điều đó có ý nghĩa.
Bạn cũng có thể xử lý tuần tự một tệp có thể lặp lại với một hàm không đồng bộ bằng cách sử dụng một hàm đệ quy. Ví dụ: đã cho một mảng a
để xử lý với hàm không đồng bộ someAsyncFunction()
:
var a = [1, 2, 3, 4, 5, 6]
function someAsyncFunction(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("someAsyncFunction: ", n)
resolve(n)
}, Math.random() * 1500)
})
}
//You can run each array sequentially with:
function sequential(arr, index = 0) {
if (index >= arr.length) return Promise.resolve()
return someAsyncFunction(arr[index])
.then(r => {
console.log("got value: ", r)
return sequential(arr, index + 1)
})
}
sequential(a).then(() => console.log("done"))
Sử dụng async chờ đợi một mảng các lời hứa có thể dễ dàng được thực thi tuần tự:
let a = [promise1, promise2, promise3];
async function func() {
for(let i=0; i<a.length; i++){
await a[i]();
}
}
func();
Lưu ý: Trong cách triển khai ở trên, nếu một lời hứa bị từ chối, phần còn lại sẽ không được thực hiện. Nếu bạn muốn tất cả các lời hứa của mình được thực hiện, hãy bọc await a[i]();
bên trong của bạntry catch
song song, tương đông
xem ví dụ này
const resolveAfterTimeout = async i => {
return new Promise(resolve => {
console.log("CALLED");
setTimeout(() => {
resolve("RESOLVED", i);
}, 5000);
});
};
const call = async () => {
const res = await Promise.all([
resolveAfterTimeout(1),
resolveAfterTimeout(2),
resolveAfterTimeout(3),
resolveAfterTimeout(4),
resolveAfterTimeout(5),
resolveAfterTimeout(6)
]);
console.log({ res });
};
call();
bằng cách chạy mã, nó sẽ điều khiển "CALLED" cho tất cả sáu lời hứa và khi chúng được giải quyết, nó sẽ điều khiển mỗi 6 phản hồi sau khi hết thời gian chờ cùng một lúc
Câu trả lời của Bergi đã giúp tôi thực hiện cuộc gọi đồng bộ. Tôi đã thêm một ví dụ bên dưới, nơi chúng tôi gọi từng hàm sau khi hàm trước đó được gọi.
function func1 (param1) {
console.log("function1 : " + param1);
}
function func2 () {
console.log("function2");
}
function func3 (param2, param3) {
console.log("function3 : " + param2 + ", " + param3);
}
function func4 (param4) {
console.log("function4 : " + param4);
}
param4 = "Kate";
//adding 3 functions to array
a=[
()=>func1("Hi"),
()=>func2(),
()=>func3("Lindsay",param4)
];
//adding 4th function
a.push(()=>func4("dad"));
//below does func1().then(func2).then(func3).then(func4)
a.reduce((p, fn) => p.then(fn), Promise.resolve());
Bạn có thể làm điều đó bằng vòng lặp for.
hàm async trả về lời hứa
async function createClient(client) {
return await Client.create(client);
}
let clients = [client1, client2, client3];
nếu bạn viết mã sau thì ứng dụng khách được tạo song song
const createdClientsArray = yield Promise.all(clients.map((client) =>
createClient(client);
));
sau đó tất cả các máy khách được tạo song song. nhưng nếu bạn muốn tạo ứng dụng khách một cách tuần tự thì bạn nên sử dụng vòng lặp for
const createdClientsArray = [];
for(let i = 0; i < clients.length; i++) {
const createdClient = yield createClient(clients[i]);
createdClientsArray.push(createdClient);
}
sau đó tất cả các máy khách được tạo tuần tự.
viết mã vui vẻ :)
Tôi đã sử dụng for để giải quyết các lời hứa tuần tự. Tôi không chắc liệu nó có giúp ích gì ở đây không nhưng đây là những gì tôi đang làm.
async function run() {
for (let val of arr) {
const res = await someQuery(val)
console.log(val)
}
}
run().then().catch()
điều này có thể trả lời một phần câu hỏi của bạn.
vâng, bạn có thể xâu chuỗi một mảng các hàm trả về lời hứa như sau ... (điều này sẽ chuyển kết quả của từng hàm sang hàm tiếp theo). tất nhiên bạn có thể chỉnh sửa nó để chuyển cùng một đối số (hoặc không có đối số) cho mỗi hàm.
function tester1(a) {
return new Promise(function(done) {
setTimeout(function() {
done(a + 1);
}, 1000);
})
}
function tester2(a) {
return new Promise(function(done) {
setTimeout(function() {
done(a * 5);
}, 1000);
})
}
function promise_chain(args, list, results) {
return new Promise(function(done, errs) {
var fn = list.shift();
if (results === undefined) results = [];
if (typeof fn === 'function') {
fn(args).then(function(result) {
results.push(result);
console.log(result);
promise_chain(result, list, results).then(done);
}, errs);
} else {
done(results);
}
});
}
promise_chain(0, [tester1, tester2, tester1, tester2, tester2]).then(console.log.bind(console), console.error.bind(console));
Tôi tình cờ xem được trang này khi đang cố gắng giải quyết một vấn đề trong NodeJS: tập hợp lại các khối tệp. Về cơ bản: Tôi có một mảng tên tệp. Tôi cần nối tất cả các tệp đó, theo đúng thứ tự, để tạo một tệp lớn. Tôi phải làm điều này không đồng bộ.
Mô-đun 'fs' của Node cung cấp appendFileSync nhưng tôi không muốn chặn máy chủ trong quá trình hoạt động này. Tôi muốn sử dụng mô-đun fs.promises và tìm cách liên kết những thứ này lại với nhau. Các ví dụ trên trang này không hoàn toàn phù hợp với tôi vì tôi thực sự cần hai thao tác: fsPromises.read () để đọc trong tệp chunk và fsPromises.appendFile () để nối với tệp đích. Có lẽ nếu tôi giỏi hơn với javascript, tôi có thể làm cho các câu trả lời trước đó phù hợp với tôi. ;-)
Tôi tình cờ thấy điều này ... https://css-tricks.com/why-using-reduce-to-sequentially-resolve-promises-works/ ... và tôi đã có thể hack cùng một giải pháp hoạt động.
TLDR:
/**
* sequentially append a list of files into a specified destination file
*/
exports.append_files = function (destinationFile, arrayOfFilenames) {
return arrayOfFilenames.reduce((previousPromise, currentFile) => {
return previousPromise.then(() => {
return fsPromises.readFile(currentFile).then(fileContents => {
return fsPromises.appendFile(destinationFile, fileContents);
});
});
}, Promise.resolve());
};
Và đây là một bài kiểm tra đơn vị hoa nhài cho nó:
const fsPromises = require('fs').promises;
const fsUtils = require( ... );
const TEMPDIR = 'temp';
describe("test append_files", function() {
it('append_files should work', async function(done) {
try {
// setup: create some files
await fsPromises.mkdir(TEMPDIR);
await fsPromises.writeFile(path.join(TEMPDIR, '1'), 'one');
await fsPromises.writeFile(path.join(TEMPDIR, '2'), 'two');
await fsPromises.writeFile(path.join(TEMPDIR, '3'), 'three');
await fsPromises.writeFile(path.join(TEMPDIR, '4'), 'four');
await fsPromises.writeFile(path.join(TEMPDIR, '5'), 'five');
const filenameArray = [];
for (var i=1; i < 6; i++) {
filenameArray.push(path.join(TEMPDIR, i.toString()));
}
const DESTFILE = path.join(TEMPDIR, 'final');
await fsUtils.append_files(DESTFILE, filenameArray);
// confirm "final" file exists
const fsStat = await fsPromises.stat(DESTFILE);
expect(fsStat.isFile()).toBeTruthy();
// confirm content of the "final" file
const expectedContent = new Buffer('onetwothreefourfive', 'utf8');
var fileContents = await fsPromises.readFile(DESTFILE);
expect(fileContents).toEqual(expectedContent);
done();
}
catch (err) {
fail(err);
}
finally {
}
});
});
Tôi hi vọng nó giúp ích cho ai đó.
Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.
Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?
Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.
Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.
Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?
Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.
Desiree Rogers, trái, và Cheryl Mayberry McKissack Chuyển sang, Fenty Beauty và Pat McGrath, có một đế chế làm đẹp mới do phụ nữ làm chủ đang trỗi dậy. Sau thương vụ mua lại mỹ phẩm Black Opal vào tháng 9, đội ngũ quyền lực của Giám đốc điều hành công ty Desiree Rogers và Chủ tịch Cheryl Mayberry McKissack đã thông báo mua lại thương hiệu làm đẹp tiên phong Fashion Fair từ người sáng lập Johnson Publishing Company (JPC).
Đối với những người có quá nhiều thời gian, tiệc tiết lộ giới tính là một cách thú vị để không cần áp đặt những định kiến hạn chế lên thai nhi trước một đối tượng bạn bè giả vờ quan tâm một cách lịch sự. Tuy nhiên, việc chỉ dựa vào những chiếc bánh nướng có màu nhân tạo để biểu thị một tiếng hoo-ha hoặc một đứa trẻ đi tè đã trở nên xa xỉ trong các bậc cha mẹ trên Instagram.
Hôm thứ Tư, cựu Bộ trưởng An ninh Nội địa Kirstjen Nielsen vì một lý do nào đó đã được đưa ra một diễn đàn để phát biểu tại Hội nghị thượng đỉnh Những người phụ nữ quyền lực nhất của Fortune. Và có thể đoán trước được, người phụ nữ giám sát các nỗ lực (đang diễn ra) của chính quyền Trump nhằm chia cắt các gia đình ở biên giới đã sử dụng thời gian của mình như một cơ hội để tự bảo vệ mình và tự nhận mình là người — và hãy hít thở sâu ở đây — “đã nói sự thật với quyền lực.
Vì thế hệ mới nhất của chiếc xe điều chỉnh được yêu thích trên thế giới hiện đã có mặt tại đây, nên chỉ có điều kiện là Toyota Racing Development sẽ đưa phiên bản Supra thế hệ thứ năm sửa đổi của riêng mình đến SEMA vào tháng tới. Toyota đã cho chúng tôi một gợi ý về những gì sẽ xảy ra trong tuần này: một chiếc Concept GR Supra 3000GT hiện đại.
Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!
Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!
Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không
Vụ kiện, nêu tên một số học khu, lập luận rằng dự luật "Không nói đồng tính" được ban hành gần đây của Florida "có hiệu quả im lặng và xóa bỏ học sinh và gia đình LGBTQ +"
Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.
Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.
Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.
Tôi ghét từ "tàu đắm". Mọi người cảm thấy thoải mái trong la bàn đạo đức của riêng mình, và khi làm như vậy, họ thấy mình vượt qua sự phán xét.