我是javascript新手,试图了解异步函数调用。 这是我的js程序:
var notify = function () {
console.log('before');
doPost('data', (res) => {
console.log('callback received');
});
console.log('after');
}
var doPost = function (data) {
console.log(data);
while (true) {
//do nothing
}
}
notify();
如果我的理解是正确的,则notify()-> doPost()是异步方式,因此应在“之前”之后立即打印“之后”。但这不会发生。我的程序等待无限循环先完成。 我知道我的理解存在漏洞。请帮忙。
我尝试了以下两个程序: 再次显示同步行为。印刷品:- 之前 数据
var notify = function () {
console.log('before');
doPost('data').then((res) => {
console.log('callback received');
});
console.log('after');
}
var doPost = function (data) {
console.log(data);
return new Promise((resolve, reject) => {
resolve('resolved');
while (true) {
//do nothing
}
});
};
notify();
但是,如果我只是删除无限运行的while循环,它将开始显示异步行为。印刷品:- 之前 数据 后 回调已收到
var notify = function () {
console.log('before');
doPost('data').then((res) => {
console.log('callback received');
});
console.log('after');
}
var doPost = function (data) {
console.log(data);
return new Promise((resolve, reject) => {
resolve('resolved');
while (false) {
//do nothing
}
});
};
notify();
这超出了我的理解。任何帮助将不胜感激。
答案 0 :(得分:2)
使用回调或Promise不一定意味着某些事情是异步的。举个例子:
console.log("before");
[1, 2, 3].forEach(console.log);
console.log("after");
这将按顺序记录所有内容,因为.forEach
会同步调用回调。但是,也有异步回调,例如setTimeout
:
console.log("before");
setTimeout(function later() {
console.log("later");
}, 0);
console.log("after");
在这里,您将看到“ before”,“ after”,“ later”,因为later
函数在计时器完成后会异步执行。为了获得异步行为,您需要一个“异步根回调”,所有基于异步的回调/承诺也都是异步的。在Javascript中,只有少数这样的“异步根”,即setTimeout
和setInterval
,fetch
以及浏览器上的DOM事件处理程序或nodejs上的所有IO。在您的代码中没有这些,因此,无论您做什么,它都是完全同步的。
要使其表现为异步,请添加异步回调:
function notify() { // function declarations look so much better than function expressions, and they are easier to handle
console.log('before');
doPost('data', (res) => {
console.log('callback received');
});
console.log('after');
}
function doPost(data, callback) { // you pass a callback, so you should take it here
console.log(data);
setTimeout(callback, 1, "result"); // call back asynchronously
}
notify();
哦和while(true)
通常表明您做错了什么事情。
答案 1 :(得分:1)
为什么要编写自己的异步函数?已经有很多不同的实用程序:
在这里查看示例。不会有帮助吗? https://caolan.github.io/async/
答案 2 :(得分:1)
在您的示例中,您似乎将异步视为并行执行,因为您希望在另一个线程上运行无限循环时主线程中的代码继续执行。并行执行是异步操作的一种形式,但是在javascript中,我们通常使用并发执行。
但是同步,异步,并行,并发到底意味着什么?
同步代码最容易使用,因为它可以提供最佳保证:
/* 1 */ doWorkSync(() => console.log("callback"));
/* 2 */ console.log("after doWorkSync");
在上面的代码中,doWorkSync
是一个同步函数,我们知道回调函数将在第2行之前执行。
在javascript中通常称为异步的并发代码为我们提供了更差的保证:
/* 1 */ doWorkAsync(() => console.log("callback"));
/* 2 */ console.log("after doWorkAsync");
在上面的代码中,我们保证在当前同步代码将完全执行后(即在第2行之后)将调用回调函数。但是我们不知道确切的时间。它可能会立即被调用,但可能会在以后被调用。
但是最难处理的代码是并行代码:
/* 1 */ doWorkParallel(() => console.log("callback"));
/* 2 */ console.log("after doWorkParallel");
在上面的代码中,我们无法保证。回调代码可以在第2行之前同时或稍后运行。因此,必须以适合任何情况的方式编写代码。
在JavaScript中编写异步(并发)函数的最简单方法是使用Promise
:
console.log("first");
Promise.resolve().then(() => console.log("last"));
console.log("second");
在then
以上的代码中,从微任务队列运行当前同步代码后,立即执行回调。
可以在JavaScript中使用Worker
s来执行并行代码:
function parallel() {
function work() {
block(200); // message from the main thread is logged while this blocks the worker
console.log("second"); // logs from the worker can be seen in the browser console
function block(time) {
const startDate = Date.now();
while (startDate + time > Date.now()) {};
}
}
new Worker(window.URL.createObjectURL(new Blob([`(${work})()`]), {
type: 'application/javascript'
}));
}
function block(time) {
const startDate = Date.now();
while (startDate + time > Date.now()) {}
}
parallel();
// timeout is needed because blob response is handled on the main thread
setTimeout(() => {
console.log("first");
block(500); // message from parallel is logged while this blocks the main thread
console.log("last");
}, 100)