Javascript 对承诺和异步等待感到困惑
我正在使用GitHub api创建应用程序,但异步函数遇到了问题。我不熟悉使用异步,因此非常感谢您的帮助。以下是我迄今为止编写的代码:Javascript 对承诺和异步等待感到困惑,javascript,async-await,es6-promise,Javascript,Async Await,Es6 Promise,我正在使用GitHub api创建应用程序,但异步函数遇到了问题。我不熟悉使用异步,因此非常感谢您的帮助。以下是我迄今为止编写的代码: const getFiles = async function(token, reponame) { var gh = new GitHub({ token: token }); reponame = reponame.split("/"); const repo = gh.getRepo(reponame[0], reponame[1
const getFiles = async function(token, reponame) {
var gh = new GitHub({
token: token
});
reponame = reponame.split("/");
const repo = gh.getRepo(reponame[0], reponame[1]);
let head = new Headers();
head.append("Authorization: ", "token " + token);
const getContents = new Promise((res, rej) => {
repo.getContents(null, "content", true, (err, files) => {
if (err) rej(err);
else return files;
}).then(files => {
let promises = [
files.map(
file =>
new Promise(res => {
fetch(file.downloadURL).then(body => {
res(body.text);
});
})
)
];
const retFiles = [];
await Promise.all(promises.map(promise => retFiles.push(promise)));
res(retFiles)
});
});
return getContents;
};
我得到的错误是在我使用wait的行中出现了意外的保留字。提前感谢所以我在这里做一些假设,如果我错了,请纠正我,我会修正它们。希望通过这样做,我可以帮助澄清您的理解 思考
async/await
的一种简单方法是取代对.then(回调)
的需求。我更喜欢在异步函数中使用wait
const getFiles = async function(token, reponame) {
try {
var gh = new GitHub({
token: token
});
reponame = reponame.split("/");
// edit: I removed await from the line below as your original code
// did not treat it as a promise
const repo = gh.getRepo(reponame[0], reponame[1]);
// unused code from your post
let head = new Headers();
head.append("Authorization: ", "token " + token);
// the await below assumes that repo.getContents
// will return a promise if a callback is not provided
const files = await repo.getContents(null, "content", true);
// updating the code below so that the file requests run in parallel.
// this means that all requests are going to fire off basically at once
// as each fetch is called
const fileRequests = files.map(file => fetch(file.downloadURL))
// you wont know which failed with the below.
const results = (await Promise.all(fileRequests)).map(res => res.text)
return results
} catch (err) {
// handle error or..
throw err;
}
};
此代码未经测试。我没有使用github的api,所以我最好猜测每个调用都在做什么。如果gh.getRepo
或repo.getContents
不返回承诺,则需要进行一些调整
如果未提供回调,您正在使用的github库将不会返回承诺:
const getFiles = async function(token, reponame) {
try {
var gh = new GitHub({
token: token
});
reponame = reponame.split("/");
const repo = await gh.getRepo(reponame[0], reponame[1]);
let head = new Headers();
head.append("Authorization: ", "token " + token);
const getContents = new Promise((res, rej) => {
repo.getContents(null, "content", true, (err, files) => {
if (err) {
return rej(err);
}
res(files)
})
})
const fileRequests = (await getContents).map(file => fetch(file.downloadURL))
return (await Promise.all(fileRequests)).map(res => res.text)
} catch (err) {
// handle error or..
throw err;
}
};
下面是一个使用async/await的示例,它使用一个新的承诺来承诺回调:
const content=document.getElementById(“内容”)
const result=document.getElementById(“结果”)
异步函数示例(){
content.innerHTML='承诺之前';
const getContents=新承诺((res,rej)=>{
设置超时(()=>{
res(‘完成’)
}, 1000)
})
const res=等待获取内容
content.innerHTML=res
返回res
}
示例()。然后((res)=>{
result.innerHTML=`I以${res}作为结果完成`
})
我发现这是修订后的代码:
const getFiles=async函数(令牌、reponame){
var gh=新的GitHub({
令牌:令牌
});
reponame=reponame.split(“/”);
常量repo=gh.getRepo(reponame[0],reponame[1]);
让文件=新承诺((res,rej)=>{
repo.getContents(null,“content”,true,(err,files)=>{
if(err)rej(err);
其他资源(档案);
});
});
让内容=新承诺(res=>{
文件。然后(文件=>{
const promises=files.reduce((结果,文件)=>{
if(file.name.endsWith(“.md”)){
结果:推(
新承诺((res,rej)=>{
repo.getContents(null,file.path,true,(err,content)=>{
if(err)rej(err);
其他的
res({
path:file.path,
内容:内容
});
});
})
);
}
返回结果;
}, []);
console.log(承诺);
res(
我保证(
promises.map(promise=>
然后(文件=>{
返回文件;
})
)
)
);
});
});
返回等待内容;
};
我仍然不知道这是否是一种“正确”的方法,但它正在工作。关键字wait
只能与异步
功能一起使用。如果您注意到,等待Promise.all(promises.map(Promise=>retFiles.push(Promise))
位于一个函数内,该函数在中传递文件
参数,然后
。只需使该函数async
和wait
在范围内工作即可。请尝试下面的代码
const getFiles = async function(token, reponame) {
var gh = new GitHub({
token: token
});
reponame = reponame.split("/");
const repo = gh.getRepo(reponame[0], reponame[1]);
let head = new Headers();
head.append("Authorization: ", "token " + token);
const getContents = new Promise((res, rej) => {
repo.getContents(null, "content", true, (err, files) => {
if (err) rej(err);
else return files;
}).then( async (files) => {
let promises = [
files.map(
file =>
new Promise(res => {
fetch(file.downloadURL).then(body => {
res(body.text);
});
})
)
];
const retFiles = [];
await Promise.all(promises.map(promise => retFiles.push(promise)));
res(retFiles)
});
});
return getContents;
};
这里有很多问题。代码非常复杂;不需要所有这些承诺和间接层和嵌套来实现您所需要的
您尝试执行的模式非常常见:
- 请求获取实体列表(文件、用户、URL…)
- 对于该列表中返回的每个实体,发出另一个请求以获取其更多信息
- 将结果作为承诺返回(它必须是承诺,因为
async
函数只能返回承诺)
这样做的方法是将问题分为几个阶段。使用wait
和async
关键字代替。然后在大多数情况下使用。为了使示例重现,我将使用一个场景,在这个场景中,我们希望获得在GitHub上创建的最新的n
GIST的用户配置文件——这基本上等同于您正在做的事情,我将留给您进行推断
第一步是获取实体(最近创建的GIST)的初始列表:
接下来,对于来自0..n
的gist数组中的每个gist,我们需要发出一个请求。确保我们没有使用wait
序列化此处的任何内容,这一点很重要:
const requests = gists.slice(0, n).map(gist =>
fetch(`https://api.github.com/users/${gist.owner.login}`)
);
现在所有的请求都在进行中,我们需要等待它们完成。这就是承诺的地方。所有都包括:
const responses = await Promise.all(requests);
最后一步是从每个响应中获取JSON,这需要另一个承诺
return await Promise.all(responses.map(e => e.json()));
这是我们可以返回的最终结果。代码如下:
const getRecentGistCreators=async(n=1)=>{
试一试{
const res=等待获取(“https://api.github.com/gists/public");
const gists=wait res.json();
const requests=gists.slice(0,n).map(gist=>
取回(`https://api.github.com/users/${gist.owner.login}`)
);
const responses=等待承诺。全部(请求);
return wait Promise.all(responses.map(e=>e.json());
}
捕捉(错误){
犯错误;
}
};
(异步()=>{
试一试{
for(Wait getRecentGistCreators的常量用户(5)){
常量elem=document.createElement(“div”);
elem.textContent=user.name;
文件.正文.附件(elem);
}
}
捕捉(错误){
犯错误;
}
})();代码>欢迎来到SO!不能使用wait
,除非它直接位于带有async
关键字的函数内部。将files=>{
更改为async files=>{
。另外,将let promises
设置为2d数组有点奇怪--只需将map
的结果直接分配给它,否则您就有一个包含promises数组的单元素数组。除了这个数组之外,您的代码还有很多问题
return await Promise.all(responses.map(e => e.json()));