鉴于以下结果,我希望@app.route("/signin",methods=["GET","POST"])
def signin():
# LOG A USER IN
#forget any user_id
session.clear()
if request.method == "GET":
return render_template("login.html")
else:
user_name = request.form.get("username")
# ensure username is provided
if not request.form.get("username"):
return "must provide username"
# ensure password is provided
elif not request.form.get("password"):
return "must provide password"
# query the database for the username
rows = db.execute("SELECT * FROM users where username = :username",{"username":user_name})
# ensure username exists
if len(rows) != 1 or not pwd_context.verify(request.form.get("password"),rows[0]["hash"]):
return "Invalid username"
# remember which user has logged in
session["user_id"] = rows[0]["id"]
出现在working
和begin
行之间。
规则:
是否可以在不更改end
文件的情况下使其正常工作?
app.js
app.js
service.js
const service = require('./service');
console.log('*********** begin ***********');
(async () => {
const results = await service.init();
})();
console.log('*********** end ***********');
结果:
exports.init = () => {
return new Promise((reject, resolve) => {
setTimeout(() => {
console.log('working...');
}, 2000);
});
};
答案 0 :(得分:5)
app.js
正在同时调用console.log('begin')
和console.log('end')
,而working
是异步。我想您可以通过更改service.js
来同时打印working
来进行更改,但这可能与您的用例不符。因此,不更改app.js
是不可能的。
如果您想要这样的东西,可以在end
之后将async
放入 await
函数中:
console.log('*********** begin ***********');
(async () => {
const results = await service.init();
console.log('*********** end ***********');
})();
答案 1 :(得分:3)
有没有一种方法可以使它在不更改app.js文件的情况下工作?
在Javascript中,您不能使异步结果同步工作。做不到有诸如Promise和async/await
之类的各种工具可帮助您使用异步操作进行编程,但是基本规则是异步结果始终将是异步的。之后,唯一需要等待运行的代码就是挂接到异步结果,并仅在收到异步结果现已完成的通知时才执行该代码。
在async
函数中,您可以使用await
编写用于异步操作的“同步查找”代码,但它仅“查找”同步并且仅在该函数中适用,并非真正同步(请参阅下面的说明)。
我希望工作出现在开始和结束行之间。
通常的误解是async
函数没有阻塞。它不会等到它内部的所有await
操作都完成并完成后才返回。
它会同步运行,直到第一个await
。在它获得第一个await
的那一点上,它将一个promise返回给调用者,并且该函数调用之后的代码继续运行。
有时,当promise解析了等待的内容,并且此时没有其他Javascript在运行时,该函数将从中断处开始运行,并运行更多操作,直到下一个await
或返回为止。如果找到另一个await
,它将再次暂停执行并将控制权返回给JS解释器以运行其他事件(非阻塞)。如果它到达功能块的末尾或遇到return语句,则可以更早解决它返回的诺言。
因此,在您的这段代码中:
const service = require('./service');
console.log('*********** begin ***********');
(async () => {
const results = await service.init();
})();
console.log('*********** end ***********');
这是事件的顺序:
console.log('*********** begin ***********');
await
为止。 service.init()
运行并返回一个承诺,await
操作将等待。届时,该函数将返回一个单独的Promise(您没有使用或关注它)。所有async
函数都返回一个诺言。console.log('*********** end ***********');
。service.init()
解析它返回的诺言,并且results
变量中填充了该诺言的解析值。虽然async
和await
很有用,但它们大多是语法糖,使编程更容易。可以将它们转换为使用.then()
而不是await
的常规promise处理。例如,假设您有以下内容:
async function foo1() {
const results = await service.init();
console.log("got results", results);
return results;
}
foo1().then(results => {
console.log("all done now");
}).catch(err => {
console.log(err);
});
该foo函数也可以这样写:
function foo2() {
try {
return service.init().then(results => {
console.log("got results", results);
return results;
});
} catch(e) {
return Promise.reject(e);
}
}
foo2().then(results => {
console.log("all done now");
}).catch(err => {
console.log(err);
});
这两个实现的行为相同。 try/catch
中的foo2()
是async
函数自动执行的操作,仅在service.init()
或foo2()
内的其他任何事物可能同步引发异常时才有用。
答案 2 :(得分:1)
Javascript是单线程,并利用所谓的事件循环来实现异步。
通过在Google上搜索event loop
,您可以找到很多资源,我相信他们能比我用抽象概念所做的更好地解释它。 https://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/
所以,回到您在app.js
中的代码
Node将立即运行这两行。
const service = require('./service');
console.log('*********** begin ***********');
此异步操作发生问题
(async () => {
const results = await service.init();
})();
上面的日志记录后,立即处理了异步操作。
但是,它是async
而不是其内容,将立即进行解析。
内部的回调函数将被扔给相应的处理程序(您正在调用异步的节点函数,因此该处理程序将成为您的节点进程)。
当节点进程空闲时,它开始检查事件循环是否完成了任何操作。您对此无能为力,但是至少我们可以确定节点现在正忙,因为之后有一个同步操作,这是
console.log('*********** end ***********');
好吧,毕竟所有代码都已运行,并且节点进程现在变得空闲,他开始发现事件循环中是否有任何事情要做,他会发现有一个
const results = await service.init();
然后该节点将可以使用此功能,这就是为什么您看到
*********** begin ***********
*********** end ***********
working...
通过使用async / await,解决方案非常简单。 但是需要注意的是,您需要将要控制异步行为的所有进程放入同一个异步块中。
答案 3 :(得分:0)
也许这会有所帮助:
const service = require('./service');
console.log('*********** begin ***********');
(async () =>/*
\
\
\
\ Will be run in a later event loop cycle
------------------------------------------------------> */ { const results = await service.init(); })();
console.log('*********** end ***********');
答案 4 :(得分:0)
简短的回答是否定的。您的匿名函数是异步的,因此它返回一个print
,因此当您开始输出Promise
时不会解决该问题。您可以将所有调用放在自己的异步函数中,然后等待结果,但这需要在异步函数上使用end
:
await
这将输出:
console.log('Top of script');
let closure = async () => {
console.log('*********** begin ***********');
let result = await (async () => {
const results = await service.init();
return results;
})();
console.log('*********** end ***********');
return result;
}
console.log('Promise not created yet')
let p = closure(); // creates promise
console.log('Promise created');
p.then(result => console.log('closure result:', result));
console.log('Bottom of script');
因此,您可以看到,当您调用Top of script
Promise not created yet
*********** begin ***********
Promise created
Bottom of script
working...
*********** end ***********
closure result: Test result
时,异步函数中的代码开始运行,然后进行超时的异步调用,因此在执行“ begin”后,代码将继续执行等待,并且外部脚本继续说“已创建承诺”,并显示为“脚本底部”。
closure()
调用告诉promise 完成后要做什么,因此,在完成超时之后,异步函数会在等待并记录“ end”后继续。当它返回完成承诺的结果并显示“关闭结果”时。
注意
p.then()
相反,应该为(reject, resolve)
。另外,您应该在超时时致电(resolve, reject)
,否则承诺将永远无法完成。我在my fiddle中使用了它:
resolve()