JS 承诺里面的承诺
Posted
技术标签:
【中文标题】JS 承诺里面的承诺【英文标题】:JS promise inside promise 【发布时间】:2017-05-18 12:31:44 【问题描述】:应该在 3 次尝试中检索位置的 getLocation()
函数改为返回 undefined
。 navigator.geolocation.getCurrentPosition()
返回正确的位置,但问题出在 Promise 处理中。
问题显然是我在 Promise 中调用了 Promise。我不允许在 geolocate()
中使用已声明为 async
的 await
关键字。
原来的电话:
var getLocationPromise = this.getLocation();
// Do something...
location = await getLocationPromise;
getLocation()
:
async getLocation()
return new Promise((resolve, reject) =>
var geolocate;
for (let i=0; i<3; i++)
geolocate = this.geolocate();
try
var location = geolocate;//CAN'T USE AWAIT INSIDE ASYNC...
resolve(location);
catch(err)
continue;
reject("Max geolocation attempts");
);
geolocate()
:
async geolocate()
return new Promise((resolve, reject) =>
navigator.geolocation.getCurrentPosition(
(position) =>
resolve(position);
,
(err) =>
reject(err);
,
enableHighAccuracy: true, timeout: 20000, maximumAge: 1000
);
);
【问题讨论】:
await getLocation().then();
=== await getLocation();
- 不是吗?
它给出了不同的结果。我对await getLocation();
返回undefined
有问题,所以我使用await getLocation().then();
,这似乎更安全
不知道为什么你在geolocate
和getLocation
上使用async
- 因为这些函数都没有使用await
//CAN'T USE AWAIT INSIDE ASYNC
- 不,这是不对的,你只能在async
中使用await
这就是问题所在,不能await
in async
【参考方案1】:
只要以下是在一个声明为异步的函数中
var getLocationPromise = this.getLocation();
// Do something...
location = await getLocationPromise;
应该没问题
看getLocation/geolocate,除非你需要单独的geolocate方法,它们应该可以合并简化为
getLocation()
var geolocate = () =>
new Promise((resolve, reject) =>
navigator.geolocation.getCurrentPosition(resolve, reject,
enableHighAccuracy: true,
timeout: 20000,
maximumAge: 1000
);
);
// this function will "retry" the supplied function (fn) cont times
var limitedPromiseRetry = (fn, cont) => fn().catch(err => cont > 0 ? limitedPromiseRetry(fn, cont-1) : Promise.reject('Max number of geolocation attempts'));
return limitedPromiseRetry(geolocate, 3);
【讨论】:
不错且紧凑的解决方案,它避免了使用双重承诺。从您的回复中,我了解到将 promise 放入 promise 不是一个好主意并且不受支持? 不,支持,只是在这种情况下不需要【参考方案2】:异步和等待
你不能在函数中使用await
没有 async
关键字。所以报错是因为executor函数是notasync
:
var getLocation = async function() // <-- this function has "async" keyword, but ...
return new Promise( function( resolve, reject ) // <-- ... this "executor" function has no "async" keyword.
var value = await geolocate(); // <-- ERROR: await is only valid in async function.
resolve( value );
)
;
但您不应该将 Promise executor 设为 async
函数。
请参阅https://eslint.org/docs/rules/no-async-promise-executor 了解更多信息。
new Promise( async function( resolve, reject ) // <-- BAD ! Don't do it !
...
)
没有嵌套的承诺
但由于getLocation
已经是一个承诺,你根本不需要嵌套的new Promise( ... )
:
var getLocation = async function() // <-- "async" makes a function to be a promise
var value = await geolocate();
// "return value" inside async function is "the same" as
// "resolve( value )" in a promise
return value;
;
因此,理论上,您可以通过以下方式解决您的问题(尽管可能有更好的方法。对于异步函数内部的“拒绝”,另请参阅How to reject in async/await syntax?)。
var getLocation = async function()
for( let i = 0; i < 3; i++ )
try
console.log('try ...', i);
var location = await geolocate(i);
console.log('... success');
return location;
catch(err)
console.log('... next try');
continue;
return Promise.reject('no success');
;
getLocation().then(function(result)
console.log('then:', result);
).catch(function(reason)
console.log('error:', reason);
)
嵌套承诺
Promise 中的 Promise 是可以的。
请注意,使用已解决的 Promise 解决 Promise 的行为“相同”,就像只解决一个 Promise。你不会注意到 .then()
函数有任何区别,无论你是解析一个值,还是在一个 Promise 中解析一个 Promise,......等等。
var nestedPromises = new Promise( function( resolve1, reject1 )
resolve1( new Promise( function( resolve2, reject2 )
resolve2( new Promise( function( resolve3, reject3 )
resolve3('resolved value');
));
));
);
nestedPromises.then( function( value )
console.log('value:', value); // <-- "value: resolved value"
)
【讨论】:
以上是关于JS 承诺里面的承诺的主要内容,如果未能解决你的问题,请参考以下文章