В следующем примере, который я написал, показано, как
Этот рабочий пример является автономным. Он будет определять простой объект запроса, который использует объект window XMLHttpRequest
для совершения вызовов. Он будет определять простую функцию, чтобы дождаться завершения кучи обещаний.
Контекст. В этом примере запрашивается конечная точка Spotify Web API для поиска объектов playlist
для заданного набора строк запроса:
[
"search?type=playlist&q=%22doom%20metal%22",
"search?type=playlist&q=Adele"
]
Для каждого элемента новый Promise запустит блок - ExecutionBlock
, проанализирует результат, заплатит новый набор обещаний на основе массива результатов, который представляет собой список объектов Spotify user
и выполняет новый HTTP-вызов в ExecutionProfileBlock
асинхронно.
Затем вы можете увидеть вложенную структуру Promise, которая позволяет вам генерировать множественные и полностью асинхронные вложенные HTTP-вызовы и присоединять результаты к каждому подмножеству вызовов через Promise.all
.
NOTE Recent Spotify search
API-интерфейсам потребуется указать токен доступа в заголовках запроса:
-H "Authorization: Bearer {your access token}"
Итак, вы должны запустить следующий пример, вам нужно поместить маркер доступа в заголовки запроса:
var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
log: function(s) {
document.getElementById("console").innerHTML += s + "
"
}
}
// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
call: function(what, response) {
var request;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // Internet Explorer
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}
// State changes
request.onreadystatechange = function() {
if (request.readyState === 4) { // Done
if (request.status === 200) { // Complete
response(request.responseText)
}
else
response();
}
}
request.open('GET', what, true);
request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
request.send(null);
}
}
//PromiseAll
var promiseAll = function(items, block, done, fail) {
var self = this;
var promises = [],
index = 0;
items.forEach(function(item) {
promises.push(function(item, i) {
return new Promise(function(resolve, reject) {
if (block) {
block.apply(this, [item, index, resolve, reject]);
}
});
}(item, ++index))
});
Promise.all(promises).then(function AcceptHandler(results) {
if (done) done(results);
}, function ErrorHandler(error) {
if (fail) fail(error);
});
}; //promiseAll
// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
var url = "https://api.spotify.com/v1/"
url += item;
console.log( url )
SimpleRequest.call(url, function(result) {
if (result) {
var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
return item.owner.href;
})
resolve(profileUrls);
}
else {
reject(new Error("call error"));
}
})
}
arr = [
"search?type=playlist&q=%22doom%20metal%22",
"search?type=playlist&q=Adele"
]
promiseAll(arr, function(item, index, resolve, reject) {
console.log("Making request [" + index + "]")
ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results
console.log("All profiles received " + results.length);
//console.log(JSON.stringify(results[0], null, 2));
///// promiseall again
var ExecutionProfileBlock = function(item, index, resolve, reject) {
SimpleRequest.call(item, function(result) {
if (result) {
var obj = JSON.parse(result);
resolve({
name: obj.display_name,
followers: obj.followers.total,
url: obj.href
});
} //result
})
} //ExecutionProfileBlock
promiseAll(results[0], function(item, index, resolve, reject) {
//console.log("Making request [" + index + "] " + item)
ExecutionProfileBlock(item, index, resolve, reject);
}, function(results) { // aggregated results
console.log("All response received " + results.length);
console.log(JSON.stringify(results, null, 2));
}
, function(error) { // Error
console.log(error);
})
/////
},
function(error) { // Error
console.log(error);
});
Я подробно рассмотрел это решение здесь .
Write-Output
следует использовать, когда вы хотите отправить данные в линии трубопровода, но не обязательно хотите отображать его на экране. Конвейер, в конце концов, напишет его на out-default
, если ничто другое не использует его в первую очередь. Write-Host
следует использовать, когда вы хотите сделать обратное. [console]::WriteLine
- это то, что Write-Host
делает за кулисами.
Запустите этот демонстрационный код и просмотрите результат.
function Test-Output {
Write-Output "Hello World"
}
function Test-Output2 {
Write-Host "Hello World" -foreground Green
}
function Receive-Output {
process { Write-Host $_ -foreground Yellow }
}
#Output piped to another function, not displayed in first.
Test-Output | Receive-Output
#Output not piped to 2nd function, only displayed in first.
Test-Output2 | Receive-Output
#Pipeline sends to Out-Default at the end.
Test-Output
Вам нужно будет заключить операцию конкатенации в круглых скобках, чтобы этот PowerShell обрабатывал конкатенацию перед тем, чтобы токенизировать список параметров для Write-Host
.
write-host ("count=" + $count)
BTW - Смотрите это видео Джеффри Сновера, объясняя, как работает трубопровод. Когда я начал изучать PowerShell, я нашел это наиболее полезным объяснением того, как работает конвейер.
Помимо того, что сказал Энди, есть еще одна разница, которая может быть важна: write-host напрямую записывает на хост и ничего не возвращает, что означает, что вы не можете перенаправить вывод, например, в файл.
---- script a.ps1 ----
write-host "hello"
Теперь запустите в PowerShell:
PS> .\a.ps1 > someFile.txt
hello
PS> type someFile.txt
PS>
Как видно, вы не можете перенаправить их в файл. Это может быть удивительно для тех, кто не осторожен.
Но если вы переключитесь на использование write-output вместо этого, вы получите перенаправление работать как ожидалось.
Из моего теста Write-Output и [Console] :: WriteLine () работают намного лучше, чем Write-Host.
В зависимости от того, сколько текста вам нужно выписать, это может быть важно.
Ниже, если результат 5 тестов каждый для Write-Host, Write-Output и [Console] :: WriteLine ().
В моем ограниченном опыте, который я нашел при работе с любые данные реального мира Мне нужно отказаться от командлетов и перейти прямо к командам нижнего уровня, чтобы получить любую достойную производительность из моих скриптов.
measure-command {$count = 0; while ($count -lt 1000) { Write-Host "hello"; $count++ }}
1312ms
1651ms
1909ms
1685ms
1788ms
measure-command { $count = 0; while ($count -lt 1000) { Write-Output "hello"; $count++ }}
97ms
105ms
94ms
105ms
98ms
measure-command { $count = 0; while ($count -lt 1000) { [console]::WriteLine("hello"); $count++ }}
158ms
105ms
124ms
99ms
95ms
Вот еще один способ выполнить эквивалент Write-Output. Просто поставьте свою строку в кавычки:
"count=$count"
Вы можете убедиться, что это работает так же, как Write-Output, запустив этот эксперимент:
"blah blah" > out.txt
Write-Output "blah blah" > out.txt
Write-Host "blah blah" > out.txt
Первые два будут выдавать " blah blah "to out.txt, но третий не будет.
" help Write-Output "дает намек на это поведение:
Этот командлет обычно используется в скриптах для отображения строк и других объектов на консоли. Однако, поскольку поведение по умолчанию заключается в отображении объектов в конце конвейера, обычно нет необходимости использовать командлет.
blockquote>В этом случае сама строка «count = $ count "- это объект в конце конвейера и отображается.