Javascript 在过滤前过早返回函数并减少完成时间
我有以下函数,它应该检查一个数组,对一些值求和,然后返回一个带和的字符串(对于Dialogflow/Google Assistant): 但是,问题是,该函数只返回您花费了0的Javascript 在过滤前过早返回函数并减少完成时间,javascript,actions-on-google,dialogflow-es,Javascript,Actions On Google,Dialogflow Es,我有以下函数,它应该检查一个数组,对一些值求和,然后返回一个带和的字符串(对于Dialogflow/Google Assistant): 但是,问题是,该函数只返回您花费了0的,其中0是reduce函数中设置的初始值,但总和实际上是30。它似乎并不等待reduce完成。 这里有什么问题?app.ask()会将响应发送回用户(并且,由于您使用的是ask()而不是tell(),因此也会说保持麦克风打开)。它返回的正是Express'Response.send()method返回的内容 它不会将字符串
,其中0是reduce函数中设置的初始值,但总和实际上是30。它似乎并不等待reduce完成。
这里有什么问题?app.ask()
会将响应发送回用户(并且,由于您使用的是ask()
而不是tell()
,因此也会说保持麦克风打开)。它返回的正是Express'Response.send()
method返回的内容
它不会将字符串返回给调用函数
如果需要该值,此时不应调用app.ask()
。只需返回值(或最终解析为该值的承诺)并调用app.ask()
恭喜,您发现了人们在使用承诺时存在的一个最大误解:承诺可以将可预测的值返回到其调用上下文
正如我们所知,我们传递给newpromise(callback)
构造函数的回调会收到两个参数,每个回调本身都会被调用
resolve(result)-异步操作的结果
拒绝(错误)-如果操作失败,则出现错误情况
假设我们定义了一个简单函数,该函数返回一个包装在对象中的字符串消息:
/**
* @typedef {Object} EchoResult
* @property {String} message
*
* @example
* {message: 'this is a message'}
*/
/**
* Wraps a message in a EchoResult.
* @param {String} msg - the message to wrap
* @return {EchoResult}
*/
const echo = function (msg) {
return {
message: msg
}
}
打电话
const result = echo('hello from echo!')
console.log(result)
我们可以期待
{ message: 'hello from echo!'}
要打印到控制台
到目前为止还不错
现在让我们做同样的事情,用承诺来包装:
/**
* Wraps a msg in an object.
* @param {String} msg - the message to wrap
* @return {Promise.<EchoResult>}
*/
const promised_echo = function (msg) {
return new Promise((resolve, reject) => {
resolve({message: msg})
})
}
我们可以期待
{ message: 'hello from promised echo!'}
{ result: undefined }
要打印到控制台
呜呜*凯旋的大张旗鼓,我们用了承诺
现在是让很多人困惑的部分
您希望我们的承诺的\u echo
函数返回什么?让我们看看
const result =
promised_echo('returns a Promise!')
console.log({result})
是的!它返回一个承诺
{ result: Promise { <pending> } }
哦!!惊喜它还返回一个承诺
{ result: Promise { <pending> } }
您的承诺链中的最后一个启用尝试返回调用您的app.ask()
函数的结果,正如我们所看到的,这是无法完成的
因此,为了能够使用传递给thenable的值,您似乎只能在thenable回调本身内部使用它
这是所有承诺中最大的误解
“但是,等等,!”,正如清晨的电视小贩所说,“还有更多!”
另一种启用方式是.catch()
函数,它是什么
这里我们发现了另一个惊喜
它的工作原理与我们发现的.then()
函数完全相同,因为它不能返回值,而且不能抛出一个错误,我们可以用它来定位代码中的问题
让我们重新定义承诺的\u echo
失败得相当不快:
const bad_promised_echo = function (msg) {
return new Promise((resolve, reject) => {
throw new Error(`FIRE! FAMINE! FLEE!! IT'S TEOTWAWKI!`)
})
}
// TEOTWAWKI = The End Of The World As We Know It!
这样,跑,
bad_promised_echo('whoops!')
将在以下情况下失败:
(node:40564) UnhandledPromiseRejectionWarning:
Unhandled promise rejection (rejection id: 1):
Error: FIRE! FAMINE! FLEE!! IT'S TEOTWAWKI!
等等,什么
我的踪迹到哪里去了
我需要我的stacktrace,这样我就可以确定错误发生在我的代码中的什么地方!(“我需要我的痛苦!这就是我,我的原因!”-由James T.Kirk转述。)
我们丢失了stacktrace,因为从Promise的回调函数的角度来看,我们没有可以从中派生它的运行时上下文
哦,我知道了!我将使用另一种启用,即.catch()
函数捕获错误
你会这么想的,但是没有骰子!因为我们仍然缺少任何运行时上下文。这次我将为你保存示例代码。相信我,或者更好的是,你自己试试看!)
承诺在程序控制的常规流程之外运行,在异步运行的昏暗世界中,我们期望在未来某个时候完成的事情
(这就是我摆出精通科学的姿势的地方,我抬起手臂,指着手指,凝视着远方,不祥地吟诵着……)
未来!
*队列swoopy Scfi theremin music*
这是异步编程真正有趣但令人困惑的地方,我们运行函数是为了实现某些目标,但我们无法知道它们何时完成,这就是异步性的本质
考虑以下代码:
request.get('http://www.example.com').then(result => {
// do something with the result here
})
你预计什么时候能完成
取决于几个不可知的因素,如网络状况、服务器负载等,无法知道get请求何时完成,除非您具有某种可怕的预感知能力
为了说明这一点,让我们回到echo示例,通过稍微延迟承诺的解决,在函数中注入一点“不可知性”:
let result
const promised_echo_in_the_future = function (msg) {
return new Promise(function(resolve, reject) {
setTimeout(() => { // make sure our function completes in the future
result = msg
resolve({
message: msg
})
}, 1) // just a smidge
})
}
然后运行它(我想你现在知道我要做什么了。)
由于在控制台日志函数尝试引用它之后,承诺的解析只发生了一点点,因此我们可以预期
{ message: 'hello from promised echo!'}
{ result: undefined }
要在控制台上打印
好的,这需要消化很多,我赞扬你的耐心
我们还有一件事要考虑。
如何使用async/await
?我们可以使用它们来公开异步函数的解析值,以便在该函数的上下文之外使用它吗
不幸的是,没有
因为async/await实际上只是一种语法糖,通过使承诺看起来是同步操作的,来隐藏承诺的复杂性
const async_echo = async function (msg) {
let res = await promised_echo(msg)
return res
}
let result = async_echo();
console.log({result})
将预期结果打印到控制台
{ result: Promise { <pending> } }
{result:Promise{}
我希望这能把事情弄清楚一点
使用承诺时,我能给出的最佳建议是:
始终在承诺链本身的回调中使用调用承诺链的任何已解析结果,并以相同的方式处理在承诺链中创建的任何错误<
{ result: undefined }
const async_echo = async function (msg) {
let res = await promised_echo(msg)
return res
}
let result = async_echo();
console.log({result})
{ result: Promise { <pending> } }