同步函数和异步函数之间的区别



我刚刚开始进行react本机开发,遇到了异步函数。有人能用外行的话解释一两件事吗。我试着读过关于它的文章,但他们都倾向于用一种非常技术性的方式来解释它,这有点令人困惑。我使用过其他语言,但javaScript不是我喜欢的。

我的疑虑是:

  1. 哪一个函数的行为更像正常函数,同步函数还是异步函数
  2. 在阅读本文时https://blog.expo.io/react-native-meets-async-functions-3e6f81111173他谈到了回报承诺和等待回应。那么,在这个过程中,什么是承诺,如果我们正在等待响应,它不应该是一个同步函数吗
  3. 当然,同步和异步功能之间的区别

Javascript是一种单线程语言,这意味着处理I/O、套接字和网络等事务的函数在执行时通常会阻塞主线程。为了能够编写并发代码,而不会用可能较慢的任务阻塞主线程,JS使用了所谓的事件循环。因此,异步函数只是一个可以放入队列中的函数,稍后可以检查函数的结果,而不会阻塞主线程。

您可以在MDN上了解更多关于事件循环的信息,并观看Philip Roberts 的演讲

当来自其他编程语言时,这是一个具有挑战性的主题。使用您的术语,"正常"函数类似于同步函数。

我推荐MDN文档等待。阅读该页面,然后运行f1示例——我在下面包含了一些增强功能:

  1. 我在console.log中添加了时间戳,这样计时就更明显了
  2. 我在调用f1()之前和之后立即添加了console.log语句

await关键字在异步函数内部并不意味着等待(或阻塞(。它分割执行流,暂停f1函数(大约2秒后将恢复(,并返回一个Promise,允许异步函数的调用方选择是否等待异步函数的结果。在下面的代码中,我们打印出对f1()的调用结果,但我们选择不等待延迟的结果,而是继续到下一个console.log

在Node.js:中运行此代码

///////////////////////////////////////////////////////////////////////
// This is just setting up timestamps for console.log
///////////////////////////////////////////////////////////////////////
const oldlog = console.log;
console.log = function () {
var args = [].slice.call(arguments);
oldlog.apply(console.log,[getTimestamp()].concat(args));
};
const getTimestamp = () => '[' + (new Date()).toISOString() + ']';
///////////////////////////////////////////////////////////////////////
// Real code starts here
///////////////////////////////////////////////////////////////////////
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
console.log('enter f1');
const x = await resolveAfter2Seconds(10);
console.log('exit f1, x =', x);
return x;
}
console.log('before f1');
const y = f1();
console.log('after f1, y =', y);

运行时,这将导致如下结果:

[2020-03-03T01:48:50.716Z] before f1
[2020-03-03T01:48:50.719Z] enter f1
[2020-03-03T01:48:50.720Z] after f1, y = Promise { <pending> }
[2020-03-03T01:48:52.725Z] exit f1, x = 10

请特别注意,在我们看到exit f1日志之前,我们看到了after f1日志。执行流被拆分,f1()被暂停,而f1()的调用方继续。f1()的执行在大约2秒后恢复。

现在,将其与调用f1()的结果await进行比较。请注意,因为我们现在使用await,所以必须将代码包装在async(实际上是一个异步IIFE(中,因为await只能在async函数内部使用。

// console.log('before f1');
// const y = f1();
// console.log('after f1, y =', y);
(async () => {
console.log('before f1');
const y = await f1();
console.log('after f1, y =', y);
})();

现在,输出如下:

[2020-03-03T02:19:18.122Z] before f1
[2020-03-03T02:19:18.124Z] enter f1
[2020-03-03T02:19:20.130Z] exit f1, x = 10
[2020-03-03T02:19:20.130Z] after f1, y = 10

请注意,现在,由于调用者选择等待调用f1()的结果,我们看到after f1exit f1日志颠倒了(使用您的术语,按"正常"顺序(。现在f1()的结果是10,而不是一个待定的Promise。

因此,这是一个有点棘手的问题,我鼓励更多的阅读和实验来掌握它。它看起来很复杂,但实际上现在编写异步JavaScript代码比在该语言中引入async/await之前更简单。

最新更新