2 回答

TA貢獻(xiàn)1817條經(jīng)驗(yàn) 獲得超14個(gè)贊
await 關(guān)鍵字可以大大簡化這一點(diǎn)。您不需要使用自遞歸函數(shù)。此演示使用隨機(jī)大小的數(shù)組偽造服務(wù)器調(diào)用。
https://jsfiddle.net/mvwahq19/1/
// setup: create a list witha random number of options.
var sourceList = [];
var numItems = 10 + Math.floor(Math.random() * 20);
for (var i = 0; i < numItems; i++)
{
sourceList.push(i);
}
sourceList.push(100);
var currentIndex = 0;
// a function which returns a promise. Imagine it is asking a server.
function getNextItem() {
var item = sourceList[currentIndex];
currentIndex++;
return new Promise(function(resolve) {
setTimeout(function() {
resolve(item);
}, 100);
});
}
async function poll() {
var collection = [];
var done = false;
while(!done) {
var item = await getNextItem();
collection.push(item);
console.log("Got another item", item);
if (item >= 100) {
done = true;
}
}
console.log("Got all items", collection);
}
poll();
你可以寫一個(gè)普通的 for 循環(huán),除了內(nèi)容使用 await。

TA貢獻(xiàn)1804條經(jīng)驗(yàn) 獲得超8個(gè)贊
當(dāng)我直接問他這個(gè)問題時(shí),他用時(shí)間和知識(shí)支持我并給出了這個(gè)很好的答案。
代碼:
//// files LINKING (those files do exist on live server - just for testing purposes):
// file1->file4(AND file101)->file7->file10 /-/ file1 content: file4 /-/ file4 content: file7 /-/ file7 content: file10 /-/ file10 content: EMPTY /-/ file101 content: EMPTY
// file2->file5(AND file102)->file8->file11 /-/ file2 content: file5 /-/ file5 content: file8 /-/ file8 content: file11 /-/ file11 content: EMPTY /-/ file102 content: EMPTY
// file3->file6(AND file103)->file9->file12 /-/ file3 content: file6 /-/ file6 content: file9 /-/ file9 content: file12 /-/ file12 content: EMPTY /-/ file103 content: EMPTY
var urls = ['http://czyprzy.vdl.pl/file1.txt', 'http://czyprzy.vdl.pl/file2.txt', 'http://czyprzy.vdl.pl/file3.txt'];
var urlsPromise = [];
function requestPromise(url) {
return new Promise(function(resolve, reject) {
request(url, function (err, resp, content) {
if (err || resp.statusCode != 200) reject(err || resp.statusCode);
else resolve(content);
});
});
}
async function urlContent(url, number) {
var arr = [];
let content = await requestPromise(url);
while (content.indexOf(';') !== -1)
{
var semiColon = content.indexOf(';');
var fileLink = content.slice(content.indexOf('file'), semiColon + 1);
content = content.replace(fileLink, ''); // we need to remove the file link so we won't iterate over it again, we will add to the array only new links
var fileLinkNumber = fileLink.replace('file', '');
fileLinkNumber = fileLinkNumber.replace(';', '');
fileLinkNumber =+ fileLinkNumber;
url = 'http://czyprzy.vdl.pl/file' + fileLinkNumber + '.txt'; // we build new address
arr.push({url, fileLinkNumber});
}
if (content.indexOf('file') !== -1)
{
var fileLinkNumber = content.slice(content.indexOf('file') + 4);
fileLinkNumber =+ fileLinkNumber;
url = 'http://czyprzy.vdl.pl/file' + fileLinkNumber + '.txt';
arr.push({url, fileLinkNumber});
}
var newArr = arr.map(function(item)
{
return urlContent(item.url, item.fileLinkNumber); // return IS important here
});
return [].concat(arr, ...await Promise.all(newArr));
}
async function doing() {
let urlsPromise = [];
for (let i = 0; i < urls.length; i++) {
urlsPromise.push(urlContent(urls[i], i + 1));
}
let results = [].concat(...await Promise.all(urlsPromise)); // flatten the array of arrays
console.log(results);
}
//// this is only to show Promise.all chaining - so you can do async loop, and then wait for some another async data - in proper chain.
var test_a = ['http://czyprzy.vdl.pl/css/1.css', 'http://czyprzy.vdl.pl/css/2.css', 'http://czyprzy.vdl.pl/css/cssa/1a.css', 'http://czyprzy.vdl.pl/css/cssa/2a.css'];
var promisesTest_a = [];
function requestStyle(url)
{
return new Promise(function(resolve, reject)
{
request(url, function(error, response, content)
{
if (response.statusCode === 200 && !error)
{resolve(content);}
else
{reject(error);}
});
});
}
for (var i = 0; i < test_a.length; i++)
{promisesTest_a.push(requestStyle(test_a[i]));}
Promise.all(promisesTest_a).then(function(promisesTest_a)
{
console.log(promisesTest_a);
}).then(function()
{
console.log('\nNow we start with @imports...\n');
}).then(function()
{
return doing();
}).then(function()
{
console.log('ALL DONE!');
});
評(píng)論:
首先解釋什么是 [...] - 解構(gòu)的休息參數(shù)(以防萬一,如果你不知道的話)。
var arr = [];
var array1 = ['one', 'two', 'three']
var array2 = [['four', 'five', ['six', 'seven']], 'eight', 'nine', 'ten'];
arr = array1.concat(array2);
console.log(arr); // it does not flattern the array - it just concatenate them (join them together)
console.log('---');
// however
arr = array1.concat(...array2);
console.log(arr); // notice the [...] - as you can see it flatern the array - 'four' and 'five' are pull out of an array - think of it as level up :) remember that it pull up WHOLE array that is deeper - so 'six' and 'seven' are now 1 level deep (up from 2 levels deep, but still in another array).
console.log('---');
// so
arr = [].concat(...arr);
console.log(arr); // hurrrray our array is flat (single array without nested elements)
console.log();
所有準(zhǔn)備下載的文件(鏈接)(urls數(shù)組中的 3 個(gè)起始文件)幾乎立即下載(同步循環(huán)包含它們的數(shù)組 - 一個(gè)接一個(gè),但很快,因?yàn)槲覀冎皇堑鼈円酝椒绞剑?/p>
然后,當(dāng)我們獲得它們的內(nèi)容時(shí)(因?yàn)槲覀兊却齼?nèi)容下載 - 所以我們?cè)谶@里得到了一個(gè)已解析的承諾數(shù)據(jù))我們開始尋找與我們已經(jīng)獲得的相關(guān)的其他可能的 url(文件)的信息,以下載它們(通過異步遞歸)。
當(dāng)我們找到有關(guān)可能的附加 url/文件的所有信息(以正則表達(dá)式數(shù)組表示 -匹配)時(shí),我們將其推送到數(shù)據(jù)數(shù)組(在我們的代碼中命名為arr)并下載它們(感謝 url 的變化)。
我們下載它們通過回歸異步 urlContent功能需要等待的requestPromise承諾(所以我們有決心/拒絕的數(shù)據(jù)urlContent所以如果需要,我們可以變異它-構(gòu)建正確的URL,以獲得下一個(gè)文件/內(nèi)容)。
依此類推,直到我們“迭代”(下載)所有文件。每次調(diào)用 urlContent 時(shí),它都會(huì)返回一個(gè)最初未決的承諾數(shù)組(promises 變量)。當(dāng)我們等待 Promise.all(promises) 時(shí),只有當(dāng)所有這些承諾都已解決時(shí),才會(huì)在那個(gè)位置恢復(fù)執(zhí)行。所以,在那一刻,我們擁有每一個(gè)承諾的價(jià)值。每一個(gè)都是一個(gè)數(shù)組。我們使用一個(gè) big concat 將所有這些數(shù)組組合成一個(gè)大數(shù)組,還包括arr的元素(我們需要記住從我們已經(jīng)下載的文件中下載的文件可能超過 1 個(gè)——這就是我們存儲(chǔ)值的原因在數(shù)據(jù)數(shù)組中 -在代碼中命名為arr - 存儲(chǔ)promiseReques函數(shù)解析/拒絕值)。這個(gè)“大”數(shù)組是用于解決承諾的值?;叵胍幌拢@個(gè) promise 是當(dāng)前函數(shù)上下文已經(jīng)返回的那個(gè),在第一個(gè) await 被執(zhí)行時(shí)。
這是很重要的部分 - 所以它 (urlContent) 返回 (await) 一個(gè)單一的承諾,并且這個(gè)(返回的)承諾被解析為一個(gè)數(shù)組作為值。請(qǐng)注意,當(dāng)遇到第一個(gè) await 時(shí),異步函數(shù)會(huì)立即將承諾返回給調(diào)用者。async 函數(shù)中的 return 語句決定了返回的 promise 的解析值是什么。在我們的例子中,這是一個(gè)數(shù)組。
因此,每次調(diào)用時(shí) urlContent 都會(huì)返回一個(gè)承諾 - 數(shù)組中已解析的值 - [...](解構(gòu)的其余參數(shù) - 返回一個(gè)最終解析為數(shù)組的承諾),由我們的異步執(zhí)行函數(shù)收集(導(dǎo)致 3 個(gè) url 被觸發(fā)在開始時(shí) - 每個(gè)人都有自己的 urlContent 函數(shù)...路徑),從 Promise.all(urlsPromise) 收集(等待?。┧羞@些數(shù)組,以及當(dāng)它們被解析時(shí)(我們等待它們被解析并由 Promise 傳遞) .all)它“返回”您的數(shù)據(jù)(結(jié)果變量)。準(zhǔn)確地說,做返回一個(gè)承諾(因?yàn)樗钱惒降模?。但是我們稱之為做的方式,我們表明我們對(duì)這個(gè)承諾解決的問題不感興趣,事實(shí)上,因?yàn)樽鰶]有 return 語句,該承諾解析為 UNDEFINED (!)。無論如何,我們不使用它 - 我們只是將結(jié)果輸出到控制臺(tái)。
與異步函數(shù)混淆的一件事是,當(dāng)函數(shù)返回時(shí)不執(zhí)行return 語句(名稱中有什么,對(duì)吧?。?)。該函數(shù)在執(zhí)行第一個(gè) await 時(shí)已經(jīng)返回。當(dāng)最終它執(zhí)行 return 語句時(shí),它并沒有真正返回一個(gè)值,而是解析“自己的”承諾;它之前返回的那個(gè)。如果我們真的想將輸出與邏輯分開,我們不應(yīng)該在那里做 console.log(results) ,而是要返回結(jié)果,然后,在我們稱之為做的地方,我們可以做 dodo.then(console.log); 現(xiàn)在我們確實(shí)使用了 do 返回的 promise!
我會(huì)保留動(dòng)詞“返回”來表示函數(shù)的調(diào)用者同步返回的內(nèi)容。我將使用“解決”作為將承諾設(shè)置為具有值的已解決狀態(tài)的操作,該值可以通過await或.then()訪問。
添加回答
舉報(bào)