我試圖強迫 Node 等待成功或失敗。我理解 fetch 回傳一個承諾,我想我告訴它如何處理兩者。
以下代碼不尊重我要求它執行的等待:
async function getAccessToken() {
...
let fetchResult = await fetch(argumentParserResult.authorizationUrl, {
method: 'POST',
body: formData,
headers: headers
}).then(success => {
console.log("Success reached. " JSON.stringify(success));
process.exit(2);
}, other => {
console.log("Other reached. " JSON.stringify(other));
process.exit(3);
});
console.log('@@ after fetch fetchResult=' fetchResult);
...
}
你可能認為 await 會導致它等待 Promise 完成,但它會離開整個函式,然后回傳給呼叫者。它不列印'@@ after fetch fetchResult=' 行。既不執行失敗,也不執行成功處理程式。
我應該指出,它似乎也沒有發出請求的 POST 呼叫。相反,它會看到該請求并做一些完全不同的事情而不會引發任何例外。
為什么它不尊重'await'關鍵字?
--- 如果我嘗試如下 try/catch 方法:
async function getAccessToken() {
console.log('@@getAccessToken BP1');
if (argumentParserResult.authenticationScheme == 'OAUTH2') {
console.log('@@getAccessToken BP2');
const fetch = require('node-fetch');
const url = argumentParserResult.resourceUrl;
console.log('@@getAccessToken BP3');
let formData = new URLSearchParams({
'grant_type': 'client_credentials',
'client_id': argumentParserResult.clientId,
'scope': argumentParserResult.clientScope,
'client_secret': argumentParserResult.clientSecret
})
console.log('@@getAccessToken BP4');
let headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
console.log('@@getAccessToken BP5');
console.log('POST ' argumentParserResult.authorizationUrl);
console.log(JSON.stringify(formData));
console.log('@@getAccessToken BP6');
try {
console.log('@@getAccessToken BP7');
const response = await fetch(argumentParserResult.authorizationUrl, {
method: 'POST',
body: formData,
headers,
});
console.log('@@getAccessToken BP8');
console.log(`Success reached.`, JSON.stringify(response));
const json = await response.json();
console.log('@@getAccessToken BP9');
console.log(`Other reached.`, json);
return json;
} catch (error) {
console.log('@@getAccessToken BP10');
console.log(`!! something went wrong`, error.message);
console.error(error);
return error;
} finally {
console.log('@@getAccessToken BP11');
console.log(`fetch finished`);
}
console.log('@@getAccessToken BP12');
}
console.log('@@getAccessToken BP13');
return "Should not have reached this point";
}
我明白了
@@getAccessToken BP1
@@getAccessToken BP2
@@getAccessToken BP3
@@getAccessToken BP4
@@getAccessToken BP5
POST https://some-url
{}
@@getAccessToken BP6
@@getAccessToken BP7
正如你所看到的,它只是在 try 塊內部,然后回傳到呼叫者,而不觸發 finally、錯誤處理程式或獲取后的日志記錄。
使用 .then 方法如下:
async function getAccessToken() {
console.log('@@getAccessToken BP1');
if (argumentParserResult.authenticationScheme == 'OAUTH2') {
console.log('@@getAccessToken BP2');
const fetch = require('node-fetch');
const url = argumentParserResult.resourceUrl;
console.log('@@BP1.9');
let formData = new URLSearchParams({
'grant_type': 'client_credentials',
'client_id': argumentParserResult.clientId,
'scope': argumentParserResult.clientScope,
'client_secret': argumentParserResult.clientSecret
})
console.log('@@getAccessToken BP3');
let headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
console.log('@@getAccessToken BP4');
console.log('POST ' argumentParserResult.authorizationUrl);
console.log(JSON.stringify(formData));
let response = await fetch(argumentParserResult.authorizationUrl, {
method: 'POST',
body: formData,
headers: headers
}).then(success => {
console.log('@@getAccessToken BP5');
console.log("Success reached. " JSON.stringify(success));
return success // !--> LOOK HERE, you should return the success variable
}).catch(e => {
console.log('@@getAccessToken BP6');
console.log(e) // !--> LOOK HERE, if you catch the error, no error will be thrown to the caller
return e
});
console.log('@@getAccessToken BP7');
console.log('@@ after fetch fetchResult=', fetchResult); // !--> LOOK HERE, this log will always log something now, it could be the responso or the error
}
console.log('@@getAccessToken BP8');
}
我得到這些日志:
@@getAccessToken BP1
@@getAccessToken BP2
@@BP1.9
@@getAccessToken BP3
@@getAccessToken BP4
POST https://login.microsoftonline.com/5a9bb941-ba53-48d3-b086-2927fea7bf01/oauth2/v2.0/token
{}
正如您在上面看到的,它只是到達提取點,然后回傳到呼叫函式。
在這兩種情況下,我都可以看到任何證據表明曾經呼叫過 fetch。
uj5u.com熱心網友回復:
嘗試這個:
async function getAccessToken() {
try {
const response = await fetch(argumentParserResult.authorizationUrl, {
method: 'POST',
body: formData,
headers,
});
console.log(`Success reached.`, JSON.stringify(response));
const json = await response.json();
console.log(`Other reached.`, json);
} catch (error) {
console.log(`!! something went wrong`, error.message);
console.error(error);
} finally {
console.log(`fetch finished`);
}
}
使用 async/await 撰寫時不需要使用 thenable 物件,而是使用 try catch bloc 捕獲錯誤,并使用awaited 函式的回傳獲取異步值。
uj5u.com熱心網友回復:
你正在混合await和then。它不是被禁止的,但在最簡單的情況下你不需要它。
沒有的解決方案then:
async function getAccessToken() {
try {
console.log('fetching data') // this log will always appear as first log, before fetching data
let fetchResult = await fetch(argumentParserResult.authorizationUrl,
{
method: 'POST',
body: formData,
headers: headers
})
let jsonR = await fetchResult.json()
console.log('fetch done') // this log will appear only if fetch is done with no errors
} catch (e) {
console.error('something went wrong', e) // this log will appear only if there was an error
}
console.log('after all') // this log will appear always, after fetch (even if fetch fails or not)
}
解決方案then:
async function getAccessToken() {
let fetchResult = await fetch(argumentParserResult.authorizationUrl, {
method: 'POST',
body: formData,
headers: headers
}).then(success => {
console.log("Success reached. " JSON.stringify(success));
return success // !--> LOOK HERE, you should return the success variable
}).catch(e => {
console.log(e) // !--> LOOK HERE, if you catch the error, no error will be thrown to the caller
return e
});
console.log('@@ after fetch fetchResult=', fetchResult); // !--> LOOK HERE, this log will always log something now, it could be the responso or the error
}
如您所見,錯誤處理在第二種解決方案中不太方便。這就是為什么你不應該與 混合await,then除非你知道你在做什么
uj5u.com熱心網友回復:
async/的重點await是擺脫回呼并使代碼更具程式性。你的代碼:
async function getAccessToken() {
...
let fetchResult = await fetch(argumentParserResult.authorizationUrl, {
method: 'POST',
body: formData,
headers: headers
})
.then( success => {
console.log("Success reached. " JSON.stringify(success));
process.exit(2);
}, other => {
console.log("Other reached. " JSON.stringify(other));
process.exit(3);
});
console.log('@@ after fetch fetchResult=' fetchResult);
...
}
失敗,因為你是
- 等待
fetch()解決并回傳結果,并且 - 在你的
then()鏈條中,你是 process.exit()在成功或失敗的情況下呼叫。
fetch()比意味著您在呼叫成功或失敗后立即終止整個程序。
如果你做這樣的事情:
async function getAccessToken() {
...
const opts = {
method: 'POST',
body: formData,
headers: headers
};
const {json, err} = await execFetch( argumentParserResult.authorizationUrl, opts );
if ( err ) {
console.log("that didn't work!", err);
process.exit(1);
}
...
}
async function execFetch( url, opts ) {
const response = { json: undefined, err: undefined };
const { res, err } = await fetch( argumentParserResult.authorizationUrl, opts )
.then( res => ({ res , err: undefined }) )
.catch( err => ({ res: undefined , err }) );
if ( err ) {
response.err = err;
}
else if ( !res.ok ) {
// non-2xx HTTP status
response.err = new Error(`${res.status}: ${res.statusText}`);
}
else {
// the 2xx happy path: deserialize the JSON response body into a JS object
response.json = res.json();
}
return response;
}
你的呼叫總是fetch()會成功,并給你一個帶有 a和一個屬性的元組。jsonerr
成功的呼叫將回傳如下內容:
{
json: { a: 1, b: 2, c: 3, },
err: undefined,
}
雖然呼叫fetch()失敗將回傳如下內容:
{
json: undefined ,
err: /* some error object with details about what went south */,
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/524492.html
