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

Asynchronous code, how does it work? Promises and callbacks

我已经尝试在网上找到答案,并且部分完成了。但是我还是不能完全理解JS怎么可以运行 ansyncronous code?

我的看法:

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的工作所以会先完成然后才出现'just a line'?所以它不是异步的,对吧? 但是如果我们有文件系统任务而不是循环,我们会有异步函数?

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

也许我只是不明白一些基础?如果你能解释我的问题,让我更明确地回答我的问题,我会很高兴。

Watch this playlist for a light overview of asynchronous Javascript.

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

要回答您的主要问题之一,异步与文件系统无关。都还在Javascript。引用我推荐的书:

异步是"when part of your program runs now, and another part of your program runs later -- there's a gap between now and later where your program isn't actively executing."

考虑你的代码:

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');

这将输出

I am callback

然后

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');

你会得到

just a line

然后

I am callback

它本质上与调用回调的函数有关。 "doSth" 不是异步函数,不管for循环要花多长时间。然而,在第二个示例中,setTimeout 是调用您的回调的函数,而 setTimeout 是一个异步函数,它在您的其余同步代码之后运行,因为这是它预期的工作方式。另一个常见的异步函数是任何类型的 AJAX 请求,提供给它的回调也将在任何其他同步代码之后调用。

我认为你是对的。

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

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

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