我如何从函数 foo 返回一个无同步请求的答案/结果?
我正在尝试从呼叫返回的值,以及将结果分配到函数内部的本地变量,并返回其中一个,但没有这些方式实际上返回答案 - 他们都返回不确定的或无论变量结果的初始值是什么。
一个不同步函数的例子,接受召回(使用 jQuery 的 ajax 函数):
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result; // It always returns `undefined`
}
使用 Node.js 的例子:
function foo() {
var result;
fs.readFile("path/to/file", function(err, data) {
result = data;
// return data; // <- I tried that one as well
});
return result; // It always returns `undefined`
}
例如,使用那时承诺的区块:
function foo() {
var result;
fetch(url).then(function(response) {
result = response;
// return response; // <- I tried that one as well
});
return result; // It always returns `undefined`
}
让我们先看看森林,先看看树木。
这里有很多有很好的详细信息的答案,我不会重复任何一个。在JavaScript中编程的关键是首先有正确的整体执行的心理模式。
您的输入点(s)是作为一个事件的结果执行. 例如,一个脚本标签与代码被加载到浏览器. (因此,这就是为什么你可能需要担心页面的准备运行你的代码,如果它需要DOM元素首先建造,等等) 您的代码执行完成 - 尽管许多无同步的呼叫它做 - 没有执行任何你的呼叫回复
但你不應該使用任何戰術工具來解決一個問題,直到你很舒服的實際問題領域. 圖描這些依賴的地圖,知道什麼需要執行時。
另一种方法是从无同步函数中返回值,是通过将结果从无同步函数中存储的对象。
下面是相同的例子:
var async = require("async");
// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
// some asynchronous operation
$.ajax({
url: '...',
success: function(response) {
result.response = response;
_callback();
}
});
});
async.parallel(asyncTasks, function(){
// result is available after performing asynchronous operation
console.log(result)
console.log('Done');
});
我正在使用结果对象来存储在无同步操作期间的值,这使得结果即使在无同步工作后也可用。
我使用这个方法很多,我会感兴趣知道这个方法有多好运作,在那里通过连续模块将结果传输回来。
让我们从一个简单的JavaScript功能开始:
function foo(){
// Do something
return 'wohoo';
}
let bar = foo(); // 'bar' is 'wohoo' here
这是一个简单的同步函数呼叫(每个字符串的代码在下一个字符串之前“完成”),结果是相同的预期。
function foo(){
setTimeout( ()=> {
return 'wohoo';
}, 1000)
}
let bar = foo() // 'bar' is undefined here
所以你去那里;那个延迟只是打破了我们所期望的功能!但是发生了什么事? 好吧,如果你看代码,它真的很合乎逻辑。
承诺实际上是关于它意味着什么:它意味着该功能保证你提供它在未来得到的任何产量。
function foo(){
return new Promise((resolve, reject) => { // I want foo() to PROMISE me something
setTimeout ( function(){
// Promise is RESOLVED, when the execution reaches this line of code
resolve('wohoo') // After 1 second, RESOLVE the promise with value 'wohoo'
}, 1000 )
})
}
let bar;
foo().then( res => {
bar = res;
console.log(bar) // Will print 'wohoo'
});
更新(与 async/await 承诺)
此分類上一篇: Catch Version:
function saveUsers(){
getUsers()
.then(users => {
saveSomewhere(users);
})
.catch(err => {
console.error(err);
})
}
async/await 版本:
async function saveUsers(){
try{
let users = await getUsers()
saveSomewhere(users);
}
catch(err){
console.error(err);
}
}
角质1
使用AngularJS的人可以通过承诺来处理这种情况。
這裡說,
承诺可以用于无与伦比的功能,并允许一个连接多个功能。
你也可以在这里找到一个好解释。
下面提到的文档中有一个例子。
promiseB = promiseA.then(
function onSuccess(result) {
return result + 1;
}
,function onError(err) {
// Handle error
}
);
// promiseB will be resolved immediately after promiseA is resolved
// and its value will be the result of promiseA incremented by 1.
孔子2及以后
在 Angular 2 中,请参见下面的例子,但建议使用 Angular 2 的观察器。
search(term: string) {
return this.http
.get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
.map((response) => response.json())
.toPromise();
}
你可以用这种方式,
search() {
this.searchService.search(this.searchField.value)
.then((result) => {
this.result = result.artists.items;
})
.catch((error) => console.error(error));
}
但TypeScript不支持本地ES6承诺,如果你想使用它,你可能需要插件。
此外,这里是承诺的规格。
如果您不使用 jQuery 在您的代码中,这个答案是为您
function foo() {
var httpRequest = new XMLHttpRequest();
httpRequest.open('GET', "/echo/json");
httpRequest.send();
return httpRequest.responseText;
}
var result = foo(); // Always ends up being 'undefined'
(注意,对于使用新的Fetch API、Angular 或承诺的人,我在下面添加了另一个答案)
你所面临的
这里有一个简单的模拟:
function getFive(){
var a;
setTimeout(function(){
a=5;
},10);
return a;
}
(重定向)
function onComplete(a){ // When the code completes, do this
alert(a);
}
function getFive(whenDone){
var a;
setTimeout(function(){
a=5;
whenDone(a);
},10);
}
使用将是:
getFive(onComplete);
同步AJAX - 不要这样做!!!
var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false); // `false` makes the request synchronous
request.send(null);
if (request.status === 200) {// That's HTTP for 'ok'
console.log(request.responseText);
}
二、修复代码
如:
var result = foo();
// Code that depends on `result` goes here
变成:
foo(function(result) {
// Code that depends on `result`
});
function myHandler(result) {
// Code that depends on `result`
}
foo(myHandler);
function foo(callback) {
var httpRequest = new XMLHttpRequest();
httpRequest.onload = function(){ // When the request is loaded
callback(httpRequest.responseText);// We're calling our method
};
httpRequest.open('GET', "/echo/json");
httpRequest.send();
}
我们现在已经使我们的 foo 函数接受一个行动运行,当 AJAX 成功完成时,我们可以通过检查答案状态是否不为 200 进行进一步扩展,并按照此进行操作(创建一个错误处理器等)。
如果你仍然很难理解这一点,请阅读MDN的AJAX开始指南。