.then()方法在JavaScript中是如何工作的?

ojsjcaue  于 2023-08-02  发布在  Java
关注(0)|答案(3)|浏览(116)

我有一些关于Promises的问题,这真的让我很困惑。

**.then()方法

在我将进入关于**.then()**方法的困惑之前,我将根据我的知识简要解释JavaScript引擎是如何工作的。
据我所知JavaScript不是一种异步语言,而是一种同步语言
JavaScript引擎同步工作,但Javascript引擎不是浏览器上运行的唯一内容
渲染引擎、setTimeout、HTTP请求等

当我们调用本机函数(例如setTimeout)时,JavaScript引擎可以与它们对话,因此setTimeout函数将调用Javascript引擎外部的程序来计时

当然,当计时器结束时,它会将回调发送到事件队列,只有在JavaScript完成所有Execution上下文之后,它才会查看事件队列
好了,现在让我们转到Promises我的问题是.then()如何知道何时调用resolve()我读过文章,他们说.then()异步工作,这对我来说听起来很奇怪,因为JavaScript是同步的,不是吗?也许我没有正确理解他们
所以我对.then()的工作原理做了自己的假设,因为我还没有找到一个来源,让我有感觉和信心,我知道.then()是如何工作的。
其中之一(我的假设)是.then方法中有两个阶段
我将使用这段代码来演示我的假设

var myPromise = new Promise(function(resolve){
                    resolve('Hello Stackoverflow !');
                 });
                 
                 myPromise.then(function(result){
                    console.log(result);
                 });

字符串
因此,基于我的假设,resolve('Hello Stackoverflow !')函数调用.then方法,.then检查以下两件事
1.如果.then()的回调参数被创建
2.如果Promise状态设置为已解决
如果两个条件都为真,那么.then()方法将把值为Hello Stackoverflow !的回调插入到事件队列中,只有在所有执行上下文弹出堆栈之后,它才会运行回调,我们将得到结果Hello Stackoverflow !
再次声明,这只是基于我的假设,也许我完全错了。
所以如果你检查我刚才说的,你可以得出结论,.then方法被调用了两次,为什么?
第一次是resolve函数调用它,但不是所有条件都为真,不为真的是.then回调参数已创建,但尚未创建,因为我们尚未到达创建回调的代码行,因此条件为假
第二次是当我们调用.then方法并创建回调时,所有条件都为true,因此它将回调插入事件队列,在所有执行上下文都弹出堆栈后,回调将被调用,我们将获得Hello Stackoverflow !
我希望你能理解我的解释
我说的对不对?
提前感谢大家:)

vlurs2pr

vlurs2pr1#

可以得出.then方法被调用了两次的结论
这不是真的。then方法的呼叫方式与任何方法的呼叫方式相同:当具有该方法调用的语句/表达式在正常执行流中被 * 求值 * 时。
示例的同步执行顺序如下所示:
1.回调函数function(resolve) {...}被传递给Promise构造函数。
1.此构造函数立即 * 执行 * 它作为参数接收的回调,并将resolvereject参数传递给它。
1.调用resolve,并将字符串传递给它。
1.因此,实现了resolve函数的promise实现会收到通知,并将promise对象的状态设置为已实现,然后注册已实现的值(字符串)。它也会将工作放入[承诺工作]队列中。

  1. promise构造函数完成执行并返回promise示例,该示例被分配给var myPromise
    1.回调函数function(result) {...}被传递给myPromise.then()方法。
    1.原生then实作会注册回呼,但不会执行它。
    1.本机then函数完成执行并返回一个新的promise。您的脚本没有捕获这个返回值,因此我们将这个新的promise标记为promiseB
    1.脚本结束,调用堆栈为空。
    现在我们进入通常称为 * 异步 * 执行的部分,它总是从作业/事件队列中的一个条目开始:
    1.主机将检查哪些作业队列中有条目,优先级高的作业队列。Promise作业队列具有很高的优先级,通常高于处理用户交互或其他外部事件的事件队列。因此,在上述步骤4中放入队列中的作业将从“承诺作业”队列中取出。
    1.执行上述作业。
    1.此作业将(逐个)调用已在myPromise对象上注册为then回调函数(如在步骤7中注册的回调函数)。注意:为了简单起见,我忽略了async/await语法。
    1.因此,在本例中,脚本中唯一的then回调函数被执行--不要与then方法本身(在步骤6中已经执行过)混淆。执行then-回调时,参数为用于实现承诺myPromise的值(在步骤4中注册的字符串)。
    1.执行console.log
  2. then回调结束执行并返回undefined
  3. promiseB使用此返回值(在本例中为undefined)来实现。
    1.作业执行完成。堆栈回退又是空的。
zdwk9cvp

zdwk9cvp2#

Promise的一个非常基本的准系统实现,它可以回答你的问题:

class Promise {
  constructor(fn) {
    this.status = "PENDING";
    this.result = null;
    this.successCB = [];
    this.errorCB = [];
    fn(this.resolve, this.reject); // This actually goes into microtask
  }

  resolve = data => {
    this.status = "SUCCESS";
    this.result = data;
    this.successCB.forEach(eachCB => eachCB(data));
    this.successCB = [];
  };

  reject = error => {
    this.status = "FAILED";
    this.result = error;
    this.errorCB.forEach(eachCB => eachCB(error));
    this.errorCB = [];
  };

  then = (successCB, errorCB) => {
    switch (this.status) {
      case "PENDING":
        this.successCB.push(successCB);
        this.errorCB.push(errorCB);
        break;
      case "SUCCESS":
        successCB(this.result);
        break;
      case "FAILED":
        errorCB(this.result);
        break;
      default:
        break;
    }
  };
}

字符串
为了保持简单,我没有考虑链接promise或高级错误处理。但是,当在解析完成之前/之后执行then时,这应该可以工作。

7kqas0il

7kqas0il3#

所以基于我的假设,解析('Hello Stackoverflow!')函数调用.then方法,.then检查以下两项
错误,resolve回调不会调用.then方法。你首先需要了解Promise是如何工作的。
在创建promise对象时,我们为promise构造函数提供了一个执行函数。

const promise = new Promise (
    () => {} // execution function
)

字符串
Promise构造器将传递2个参数(即2回调函数)到这个执行函数并调用它。因此,我们编写2个参数(通常命名为resolve,reject)来使用此参数

const promise = new Promise (
    (resolve, reject) => {} // resolve and reject parameter catches the argument provided to the executor function 
)


当Promise构造函数调用这个执行函数时,根据你的逻辑,resolve或reject将被调用(带有一个参数)。如果调用resolve,则Promise状态将设置为Fulfiled。否则,如果调用reject,则promise状态将被设置为rejected。

  • 当这个承诺被解决时(即或者被满足或者被拒绝),它将把存储的回调函数添加到微任务队列中

要使用/消费promise,您可以使用promise对象提供的方法,例如:.then方法。使用.then方法时,如果promise处于挂起状态,则.then方法将回调存储在promise对象中

promise.then(
    val => console.log(val); // this callback function will be stored in the pending promise object, else if is already settled callback will be added to the microtask queue
)


否则,如果promise已经被设置,则回调函数将被添加到微任务队列中

**注意:**如果你链接的是另一个.then方法,它的回调会被追加到前一个.then方法返回的新promise对象上

  • .catch方法的工作方式与.then方法相同

相关问题