异步代码,它是如何工作的?承诺和回调

时间:2017-09-19 08:26:31

标签: javascript asynchronous ecmascript-6 promise asynccallback

我试图在网上找到答案,并且部分地做了。但我还是不能完全理解JS如何运行反同步代码?

我看到的事情:

JS为我们提供了异步编程的能力。这意味着我们可以开始第一个任务,然后当一个任务正在进行时,我们可以开始第二个任务,等等。 在js可以开始第二个任务之前,它应该从前一个任务中解放出来。它可以通过两种方式实现:

  • js由它自己的结束任务(应该由js处理的代码)
  • js可以启动应该由文件系统处理的任务。在这种情况下,js执行其工作,将任务传递给文件系统并开始处理其他排队任务。当js被释放并且文件系统返回结果时,js可以继续该任务。

因此,我们不能通过编写下一个代码来实现异步:

function doSth( callback ) {
    let arr = [];

    for ( let i=1e6; i > 0; i-- )
        arr.push( i );

    callback();
}

doSth( console.log.bind( null, 'I am callback' );
console.log( 'just a line' );

由于doSth()仅包含js的工作,它将首先完成,然后只显示一行'?所以它不是同步的,对吧? 但是如果我们将文件系统任务放在循环中,我们将具有异步功能吗?

还有一个问题:承诺真的是同步吗?它们如何是异步的(我的意思是,在承诺处理时可以处理其他任务),或者承诺只是模仿异步代码? *我知道,还有额外的承诺队列。

Maby我只是不了解一些基础?如果你能解释我,让我的问题更加明确,我会很高兴。

2 个答案:

答案 0 :(得分:0)

Watch this playlist for a light overview of asynchronous Javascript.

But if you really want to understand all the details, read this book.

要回答您的一个主要问题,异步与文件系统无关。它仍然是Javascript。引用我推荐的那本书:

Asynchrony是“当你的程序的一部分现在运行,程序的另一部分稍后运行 - 现在和之后的程序没有正在执行的程序之间存在差距。”

考虑你的代码:

function doSth(callback) {
  let arr = [];
  for (let i=1e6; i > 0; i--){
    arr.push(i);
  }
  callback();
}

doSth(console.log.bind(null, 'I am callback'));
console.log('just a line');

这将输出

  

我是回电

然后

  

只是一行

但是,如果您将代码更改为:

function doSth(callback) {
  let arr = [];
  for (let i=1e6; i > 0; i--){
    arr.push(i);
  }
  setTimeout(callback, 0);
}

doSth(console.log.bind(null, 'I am callback'));
console.log('just a line');

你会得到

  

只是一行

然后

  

我是回电

它基本上与调用回调的函数有关。无论for循环需要多长时间,“doSth”都不是异步函数。但是,在第二个例子中,setTimeout是调用你的回调的函数,而setTimeout是一个异步函数,它在你的同步代码的其余部分之后运行,因为它是它的工作方式。另一个常见的异步函数是任何类型的AJAX请求,并且提供给它的回调也将在任何其他同步代码之后调用。

答案 1 :(得分:0)

我认为你做得对。

函数doSth是同步的,将阻塞主线程直到它完成。您只提供回调API,但这并不意味着它会神奇地变为异步。

事实是,您编写的所有JS代码都是同步的,除非您使用定义为异步的核心JS函数(例如fs.readFilesetTimeout$.ajax({...}).done)。如果没有它们,你就无法创建异步行为,你必须从头开始编写自己的JS核心,并使用事件循环(事实上,我鼓励你去研究javascript event loop是什么,我相信它会为你澄清很多东西,并会让你更好地了解核心中发生的事情。所有第三方库都实现了异步行为,因为它们使用这些核心功能并使用自己的代码包装它们,从而提供更优雅和更高级别的API。

这同样适用于承诺。是的,它们是异步的,但是只要你用异步代码填充它们。实际上,它们有一些额外的开销并且不会立即运行代码,但是如果单个promise只包含同步代码,那么它的最终执行将阻塞主线程直到它完成。