简体   繁体   English

了解 setTimeout 及其在 JavaScript Promises 中的实现

[英]Understanding setTimeout and its implementation in JavaScript Promises

I have the following code:我有以下代码:

function MyPromise(configFunction) {
  let nextSuccessCallBack = undefined;
  let nextResolve = undefined;
  configFunction(function(message){
    setTimeout(function(){
      if(nextSuccessCallBack) {
        var result = nextSuccessCallBack(message);
        if(result && result.then) {
          result.then(nextResolve);
        } else {
          nextResolve && nextResolve(result);
        }
      }
    })
  });

  return {
    then: function(successCallback) {
      nextSuccessCallBack = successCallback;
      return new MyPromise(function(resolve) {
        nextResolve = resolve;
      })
    }
  }
}

new MyPromise(function(resolve, reject) {
  resolve('new message');
}).then(function(message) {
  console.log(message);
  return 'another message'
}).then(function(message) {
  console.log(message)
  console.log('here')
})

In this example, it seems that the nextSuccessCallBack is set to be the callback functions within .then , then its value within the setTimeout function is now populated.在此示例中,似乎nextSuccessCallBack设置为 .then 中的回调函数,然后填充 setTimeout .then中的值。 However, this confuses me.然而,这让我很困惑。 I thought that when we reach the return statement in the constructor, we return the object and effectively stop the function?我以为当我们到达构造函数中的return语句时,我们返回object并有效地停止function? If that the case then how does the program even get to the setTimeout ?如果是这种情况,那么程序如何到达setTimeout

This is not a correct Promise implementation.这不是正确的 Promise 实现。 It clearly has no capabilities for rejections, but also for the implemented fulfilment feature it does not comply with the Promises/A+ specification .它显然没有拒绝的能力,而且对于实现的功能,它也不符合Promises/A+ 规范 Just to give two examples:仅举两个例子:

  1. It does not comply with rule 2.1.2.2不符合规则 2.1.2.2

    When fulfilled, a promise must have a value, which must not change.完成后,promise 必须有一个值,该值不得更改。

    ....nor with rule 2.2.2.3: ....也不符合规则 2.2.2.3:

    If onFulfilled is a function it must not be called more than once.如果onFulfilled是 function,则不能多次调用它。

    In your implementation, if you would add a second call to resolve :在您的实现中,如果您要添加第二个调用来resolve

     new MyPromise(function(resolve, reject) { resolve('new message'); resolve('new message2'); }).then((function(message) { console.log(message); //... etc })

    ...then both calls to resolve would fire the then callback, and show that the promised value was modified after the first time it was set. ...然后对resolve的两个调用都会触发then回调,并显示承诺的值在第一次设置后被修改。 This is in complete violation of the principle of promises: promises can only resolve once.这完全违反了 Promise 的原则:Promise 只能解决一次。

  2. It does not comply with rule 2.2.6:它不符合规则 2.2.6:

    then may be called multiple times on the same promise. then可以在同一个 promise 上多次调用。

    • If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then .如果/当promise完成时,所有相应的onFulfilled回调必须按照它们对then的原始调用的顺序执行。

    This does not happen if we use the following code:如果我们使用以下代码,则不会发生这种情况:

     let p = new MyPromise(resolve => resolve("value")); p.then(console.log); // This callback is called p.then(console.log); // This callback is not called -> violation!

These are basic shortcomings, and this is just the tip of the iceberg.这些都是基本的缺点,而这只是冰山一角。

If you are interested in how it could be implemented in compliance with Promise/A+, then have a look at one I did a few years ago with a step-by-step explanation.如果您对如何按照 Promise/A+ 实施它感兴趣,那么请看一下我几年前所做的一步一步的解释。

As to your question至于你的问题

how does the program even get to the setTimeout ?程序甚至如何到达setTimeout

When your main code executes this:当您的主代码执行此操作时:

new MyPromise(function(resolve, reject) {
  resolve('new message');
})

...then the parameter variable configFunction is initialised with that callback function. ...然后使用该回调 function 初始化参数变量configFunction The MyPromise constructor calls it, passing it the following callback as first argument: MyPromise构造函数调用它,将以下回调作为第一个参数传递给它:

  function(message){
    setTimeout(function(){
      if(nextSuccessCallBack) {
        var result = nextSuccessCallBack(message);
        if(result && result.then) {
          result.then(nextResolve);
        } else {
          nextResolve && nextResolve(result);
        }
      }
    })
  }

So that means that resolve in your main code's callback function is initialised with the above callback function.所以这意味着在你的主代码的回调 function 中resolve是用上面的回调 function 初始化的。 Then your main code's callback function calls resolve with a string argument.然后您的主代码的回调 function 使用字符串参数调用resolve Since resolve is the above callback function, we can see it gets executed with message initialised to "new message".由于resolve是上述回调 function,我们可以看到它在message初始化为“新消息”的情况下执行。 This function executes setTimeout .这个 function 执行setTimeout

The code in the snippet does solve the purpose but, it is confusing as is a bad implementation of a Promise according to the way MDN Uses Promises in JavaScript for better code efficiency and understanding.片段中的代码确实解决了这个目的,但是它令人困惑,因为根据MDN 在 JavaScript 中使用 Promises 以提高代码效率和理解的方式, Promise的错误实现也是如此。

The above code can also be written this way:上面的代码也可以这样写:

const examplePromise = new Promise((resolve, reject) => {
    resolve("Another Message");
});

console.log("New Message");
examplePromise.then((message) => {
    console.log(message);
});

Now, for better understading of the concept of Promises in JavaScript, I'll take another example:现在,为了更好地理解 JavaScript 中 Promises 的概念,我再举一个例子:

Let's say I want to create a program which says hello and then after 2 seconds says How Are You?假设我想创建一个程序,它会说你好,然后在 2 秒后说你好吗?

There are two ways of solving this有两种方法可以解决这个问题

  • Just using the setTimeout() function which executes a function after certain period of time只需使用setTimeout() function 在一段时间后执行 function
  • Using promises with setTimeout()通过setTimeout()使用 Promise

Case I (Using setTimeout() ):案例一(使用setTimeout() ):

console.log("hello"); //Saying hello for the first time

setTimeout(function () {
    console.log("How Are You?");
}, 2000); //2000 milliseconds is 2 seconds

Case II (Using Promises )案例二(使用承诺

console.log("hello");

const example = new Promise((resolve) => {
    setTimeout(() => {
        resolve("How Are You?");
    }, 2000);
});

example.then((message) => {
    console.log(message);
});

Now, for simple cases like logging a message after 2 seconds do not require Promises .现在,对于简单的情况,例如 2 秒后记录一条消息,不需要 Promises You may use them (No problem) but actually, Promises are used in cases where, you wait for a function to execute a Database Query or you need to wait for a server to give you some HTML Response or while using WebAPIs, etc.您可以使用它们(没问题),但实际上,Promise 用于以下情况:您等待Promises执行数据库查询,或者您需要等待服务器给您一些 HTML 响应或使用 WebAPI 等。

PS: setTimeout() is just an example. PS: setTimeout()只是一个例子。 It is not a rule that you always have to use setTimeout() while writing a Promise .在编写Promise时,并非总是必须使用setTimeout() If you are fetching data using a WebAPI, you usually write $.ajax(...).then(...) or fetch(...).then(...) instead of setTimeout()如果您使用 WebAPI 获取数据,您通常编写$.ajax(...).then(...)fetch(...).then(...)而不是setTimeout()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM