Javascript 如何延迟代码的执行,直到fetch返回值
我创建了以下两个函数来从后端获取Javascript 如何延迟代码的执行,直到fetch返回值,javascript,fetch,Javascript,Fetch,我创建了以下两个函数来从后端获取JWT令牌,并将其存储在localStorage中。逻辑看起来很简单,但不起作用,因为在解析令牌的值之前,代码会继续执行。因此,链中需要令牌的函数无法获得该令牌。最终,它确实获得了令牌并将其存储在localStorage中,但到那时,启动链中的所有函数都无法获得有效的令牌 当我的React应用程序启动时,我一开始就在做所有这些。因此,我们的想法是获取令牌,然后执行其余的启动步骤 因此,我在我的应用程序的入口点调用myStartup()函数。我这样做是第一步。从那里
JWT令牌
,并将其存储在localStorage
中。逻辑看起来很简单,但不起作用,因为在解析令牌的值之前,代码会继续执行。因此,链中需要令牌的函数无法获得该令牌。最终,它确实获得了令牌并将其存储在localStorage
中,但到那时,启动链中的所有函数都无法获得有效的令牌
当我的React应用程序启动时,我一开始就在做所有这些。因此,我们的想法是获取令牌,然后执行其余的启动步骤
因此,我在我的应用程序的入口点调用myStartup()
函数。我这样做是第一步。从那里,剩余的启动函数作为回调传递
export const getJwtTokenFromApi = () => {
var request = new Request('/api/token', {
method: 'GET',
mode: 'cors',
credentials: 'include'
});
fetch(request)
.then((response) => {
response.text()
.then((token) => {
if(token.length > 0) {
localStorage.setItem('myToken', token);
return token;
} else {
return null;
}
})
})
.catch(err => {
});
}
export const getJwtToken = () => {
let token = localStorage.getItem('myToken');
if (token == null)
token = getJwtTokenFromApi();
return token;
}
export const myStartup = (callback) => {
const token = getJwtToken();
callback(token);
}
最终发生的情况是,需要令牌的调用函数不会延迟到令牌被接收时,因此它最终会接收未定义的
如何确保延迟执行需要令牌的函数,直到我拥有合法令牌——或者至少有一个表示API调用失败的空值?您的函数
getJwtToken
应该返回承诺:
export const getJwtToken = () => {
let token = localStorage.getItem('myToken');
return token ? Promise.resolve(token) : getJwtTokenFromApi(storeToken)
}
在您的呼叫者中,令牌将包装在内部返回的承诺中:
getJwtToken().then(token => doSomething(token))
您的函数
getJwtToken
应该返回承诺:
export const getJwtToken = () => {
let token = localStorage.getItem('myToken');
return token ? Promise.resolve(token) : getJwtTokenFromApi(storeToken)
}
在您的呼叫者中,令牌将包装在内部返回的承诺中:
getJwtToken().then(token => doSomething(token))
我用下面的代码实现了这一点,但我认为它不是很优雅 本质上,我将多个函数合并为一个,并添加了一个回调参数,以便创建一个启动函数链。如果没有收到回调,我只返回令牌,以使
getJwtToken()
成为一个多用途函数,即调用它来获取令牌或传递期望令牌的函数
我真的希望有单独的功能,以便不是所有的关注点都在一个功能中。另外,当我需要只获取令牌时,不要疯狂地使用回调参数
我想发布代码,这样我可以得到一些建议,使它更加健壮和优雅
export const getJwtToken = (callback) => {
// If token is already in localStorage, get it and return it.
const token = localStorage.getItem('myToken');
if (token != null)
return token;
// Token is not in localStorage. Get it from API
var request = new Request('/api/token', {
method: 'GET',
mode: 'cors',
credentials: 'include'
});
fetch(request)
.then((response) => {
response.text()
.then((token) => {
if (token.length > 0) {
// First, save it in localStorage
localStorage.setItem('myToken', token);
// If no callback function received, just return token
if (typeof callback == "undefined") {
return token;
} else {
callback(token);
}
}
})
})
.catch(err => {
});
}
我用下面的代码实现了这一点,但我认为它不是很优雅 本质上,我将多个函数合并为一个,并添加了一个回调参数,以便创建一个启动函数链。如果没有收到回调,我只返回令牌,以使
getJwtToken()
成为一个多用途函数,即调用它来获取令牌或传递期望令牌的函数
我真的希望有单独的功能,以便不是所有的关注点都在一个功能中。另外,当我需要只获取令牌时,不要疯狂地使用回调参数
我想发布代码,这样我可以得到一些建议,使它更加健壮和优雅
export const getJwtToken = (callback) => {
// If token is already in localStorage, get it and return it.
const token = localStorage.getItem('myToken');
if (token != null)
return token;
// Token is not in localStorage. Get it from API
var request = new Request('/api/token', {
method: 'GET',
mode: 'cors',
credentials: 'include'
});
fetch(request)
.then((response) => {
response.text()
.then((token) => {
if (token.length > 0) {
// First, save it in localStorage
localStorage.setItem('myToken', token);
// If no callback function received, just return token
if (typeof callback == "undefined") {
return token;
} else {
callback(token);
}
}
})
})
.catch(err => {
});
}
根本的问题是,您没有像处理异步内容一样处理所有异步内容。这是一个相当复杂的工作流,阻塞和非阻塞任务混杂在一起,这意味着我们需要在整个过程中应用异步模式。让我们一步一步地完成脚本中的一个函数
这似乎是脚本的入口点:
export const myStartup = (callback) => {
const token = getJwtToken();
callback(token);
}
它不会工作,因为getJwtToken
是异步的,这意味着它的值将不可用于下一行的callback
我们如何知道getJwtToken
是异步的?因为getJwtToken
调用getJwtTokenFromApi
,调用fetch
(规范告诉我们是异步的)。因为getJwtToken
包装了异步行为,所以它本身是异步的
由于getJwtToken
是异步的,我们知道token
在callback
需要时在第二行不可用。事实上,token
在该范围内永远不可用,因为getJwtToken
返回一个承诺,其解析值将仅在处理程序内可用。因此,第1步是重写此函数:
export const myStartup = (callback) => {
getJwtToken() // returns a Promise
.then((token) => { // token is available inside Promise's .then
callback(token);
})
}
现在我们看一下getJwtToken
,记住它必须返回一个承诺,因为我们刚刚做了更改
export const getJwtToken = () => {
let token = localStorage.getItem('myToken');
if (token == null)
token = getJwtTokenFromApi();
return token;
}
这是一个有趣的案例,因为getJwtToken
实现了分支行为,一个分支是同步的,另一个不是。(localStorage.getItem
阻塞,但getJwtTokenFromApi
是异步的。)处理此类情况的唯一方法是使整个函数异步:确保它始终返回承诺,即使它所需的数据可以从同步源获得
由于localStorage.getItem
是同步的,如果我们喜欢它给我们的值,我们会在返回它之前将该值包装在承诺中。否则,我们只能返回由getJwtTokenFromApi
返回的承诺:
export const getJwtToken = () => {
let token = localStorage.getItem('myToken')
if(token !== null)
return Promise.resolve(token);
return getJwtTokenFromApi();
}
现在,无论我们处于哪种情况,这个函数都将返回一个包含令牌的承诺
最后,我们来看看getJwtTokenFromApi
,它做了一些事情:
- 它构造一个
请求
- 它执行一个请求(异步)
- 如果成功,它将响应转换为文本(异步)
- 它检查文本
如果所有这些都解决了,它希望返回文本值。但是这些任务中有一半是异步的,这也意味着整个函数必须是异步的。以下是您开始使用的更精简版本:
export const getJwtTokenFromApi = () => {
var request = new Request('/api/token', {});
fetch(request)
.then((response) => {
response.text()
.then((token) => {
if(token.length > 0) {
localStorage.setItem('myToken', token);
return token;
} else {
return null;
}
})
})
}
这里最大的问题是您没有返回fetch
。这一点很重要,因为嵌套在其中的其他return
语句不适用于整个函数。此函数不会返回任何写入的内容,尽管它将执行XHR调用。因此,第一个修复方法是返回fetch<
export const getJwtTokenFromApi = () => {
var request = new Request('/api/token', {
method: 'GET',
mode: 'cors',
credentials: 'include'
});
return fetch(request)
.then((response) => response.text())
.then((token) => {
if(token.length > 0) {
localStorage.setItem('myToken', token);
return token;
}
return null;
})
})
}
var x = Promise.resolve( Promise.resolve( Promise.resolve ( 10 )))
var y = Promise.resolve( 10 )
.then((value) => {
// value === 10
})
export const getJwtTokenFromApi = () => {
var request = new Request('/api/token', {
method: 'GET',
mode: 'cors',
credentials: 'include'
});
return fetch(request)
.then((response) => response.text())
.then((token) => {
if(token.length > 0) {
localStorage.setItem('myToken', token);
return token;
}
return null;
})
})
}
export const getJwtToken = () => {
let token = localStorage.getItem('myToken')
if(token !== null)
return Promise.resolve(token);
return getJwtTokenFromApi();
}
export const myStartup = (callback) => {
getJwtToken()
.then((token) => {
callback(token);
})
}
export const myStartup = () => {
return getJwtToken();
}