为什么承诺首先打印所有成功然后是拒绝后,即使我为其编写代码随机出现
var errors = 0;
var successes = 0;
var p1;
for (var i = 0; i < 10; i++) {
  p1 = new Promise(function(resolve,reject) {
    var num = Math.random();
    if (num < .5) {
      resolve(num);
    } else {
      reject(num)
    }
  });

  p1.then(function success(res) {
    successes++;
    console.log("*Success:* " + res)
  }).catch(function error(error) {
    errors++
    console.log("*Error:* " + error)
  });
}

OUTPUT

VM331:16 *Success:* 0.28122982053146894
VM331:16 *Success:* 0.30950619874924445
VM331:16 *Success:* 0.4631742111936423
VM331:16 *Success:* 0.059198322061176256
VM331:16 *Success:* 0.17961879374514966
VM331:16 *Success:* 0.24027158041021068
VM331:19 *Error:* 0.9116586303879894
VM331:19 *Error:* 0.7676575145407345
VM331:19 *Error:* 0.5289135948801782
VM331:19 *Error:* 0.5581542856881132

解决方法

它与异步代码的工作方式有关

.then().catch() – 必须等待队列两次(嗯,我需要解释一下)

.then()只有一次

Promise本质上是异步的…在你的代码中,当一个promise解析时,.then代码放在​​微任务上?队列…并依次处理

当它拒绝时,因为.then没有onRejected回调,那么,你的情况下的promise链.catch中的下一个处理程序是否被添加到microtask中?队列 – 但到那时,所有.then代码都已执行

尝试使用.then(onSuccess,onError),你会得到你期望的

var errors = 0;
var successes = 0;
var p1;
for (var i = 0; i < 10; i++) {
    p1 = new Promise(function(resolve,reject) {
        var num = Math.random();
        if (num < .5) {
            resolve(num);
        } else {
            reject(num);
        }
    });
    p1.then(function success(res) {
        successes++;
        console.log("*Success:* " + res);
    },function error(error) {
        errors++;
        console.log("*Error:* " + error);
    });
}

获得你想要的东西的另一种方式(至少在原生的Promises中)是

var errors = 0;
var successes = 0;
var p1;
for (let i = 0; i < 10; i++) {
    p1 = new Promise(function(resolve,reject) {
      setTimeout(() => {
            var num = Math.random();
            if (num < .5) {
                resolve(`${i} ${num}`);
            } else {
                reject(`${i} ${num}`)
            }
        });
    });
    p1.then(function success(res) {
        successes++;
        console.log("*Success:* " + res)
    }).catch(function error(error) {
        errors++
        console.log("*  Error:* " + error)
    });
}

这是因为setTimeout会延迟解析/拒绝

An in-depth explanation

首先要做的事情……你需要了解它.然后才是

.then(onFullfilled,onRejected)

并返回一个Promise

接下来,.catch只是“语法糖”

.then(null,onRejected)

实际上,在大多数Promise库中(在它们出生之前)它被定义为

Promise.prototype.catch = function (onRejected) {
    return this.then(null,onRejected);
};

是的……所以让我们来看看你的代码的一个简单的简单版本 – 为了简洁,只使用三个承诺

function executorFunction(resolve,reject) {
    const num = Math.random();
    if (num < .5) {
      resolve(num);
    } else {
      reject(num)
    }
}
let successes = 0,errors = 0;
function success(res) {
    successes++;
    console.log("*Success:* " + res)
}
function error(error) {
    errors++
    console.log("*Error:* " + error)
}

const p1 = new Promise(executorFunction);
p1.then(success).catch(error);

const p2 = new Promise(executorFunction);
p2.then(success).catch(error);

const p3 = new Promise(executorFunction);
p3.then(success).catch(error);

您可以运行它并看到它产生相同的成功和错误顺序

现在,让我们稍微改变一下,这样我们总能获得成功/失败/成功

function executorFunction(num,fail) {
    return (resolve,reject) => {
        if (fail) {
          reject(num);
        } else {
          resolve(num)
        }
    };
}
function success(res) {
    console.log("*Success:* " + res)
}
function error(error) {
    console.log("*Error:* " + error)
}

const p1 = new Promise(executorFunction(1,false));
p1.then(success).catch(error);

const p2 = new Promise(executorFunction(2,true));
p2.then(success).catch(error);

const p3 = new Promise(executorFunction(3,false));
p3.then(success).catch(error);

这总是输出

*Success:* 1
*Success:* 3
*Error:* 2

所以我们看到你在问题中看到的顺序 – 到目前为止一切顺利

现在,让我们以扩展形式重写.then / .catch

function executorFunction(num,true));
p1.then(success,null).then(null,error);

const p2 = new Promise(executorFunction(2,false));
p2.then(success,error);

让我们只使用两个承诺,FirsT拒绝…我们知道这将输出成功2然后错误1 – 即以我们期望的相反顺序

那么让我们来分析一下发生了什么

因为您在Promise构造函数executorFunction中同步解析/拒绝

const p1 = new Promise(executorFunction(1,false));

是一个已经解决的Promise – 对于p2已经达到2,并且对于p1被拒绝,原因为1,但它永远不会处于Pending状态.所以,当一个承诺没有待处理(它已经解决,但这意味着要么已经完成或被拒绝,但是术语已经混淆了,所以我会继续说“没有待定”),任何“处理程序”都被添加到微任务队列 – 所以在所有代码的末尾,微任务队列看起来像

**microtask queue**
(resolved:2).then(success,error); // added second
(rejected:1).then(success,error); // added first

现在JS引擎,因为没有任何运行,处理微任务队列(顺便说一下队列的头部在底部)

>它看到一个被拒绝的承诺(1),但.then没有被拒绝的函数,所以承诺值继承了链
>.然后返回此拒绝的承诺与原始拒绝原因
>这个承诺,因为它有一个处理程序(原始代码中的.catch)被添加到微任务队列中

.

**microtask queue**
(rejected:1)>(rejected:1).then(null,error);         // added third
(resolved:2).then(success,error).then(null,error); // added second

现在处理下一个微任务

>它看到了一个已解决的承诺(2)所以要求成功
>输出成功2
> .then返回一个promise,因为你的success函数没有返回,这是return undefined,promise被解析为undefined
>这个承诺,因为它有一个处理程序(原始代码中的.catch)被添加到微任务队列中

.

**microtask queue**
(resolved:2)>(resolved:undefined).then(null,error); // added fourth
(rejected:1)>(rejected:1).then(null,error);         // added third

>它看到一个被拒绝的promise(1)并且有一个onrejected处理程序调用错误
>输出错误1
> .then返回一个promise,没有处理程序,因此没有任何东西被添加到微任务队列中

.

**microtask queue**
(resolved:2)>(resolved:undefined).then(null,error); // added fourth

现在处理下一个微任务

>它看到一个已解决的承诺(2,现在未定义) – 但没有onSuccess处理程序
> .then返回一个promise,因此没有任何东西被添加到微任务队列中

.

**microtask queue**
**empty**

why using .then(onFullfilled,onRejected) results in the expected order

好的,现在,如果我们编写代码

function executorFunction(num,reject) => {
        if (fail) {
          reject(num);
        } else {
          resolve(num)
        }
    };
}
function success(res) {
    console.log("*Success:* " + res)
}
function error(error) {
    console.log("*Error:* " + error)
}
const p1 = new Promise(executorFunction(1,error);

微任务队列开始,就像

**microtask queue**
(resolved:2).then(success,error); // added first

现在处理下一个微任务

>它看到被拒绝的承诺(1)所以调用错误
>输出错误1
> .then返回一个promise,因此没有任何东西被添加到微任务队列中

.

**microtask queue**
(resolved:2).then(success,error); // added second

>它看到了一个已解决的承诺(2)所以要求成功
>输出成功2
> .then返回一个promise,因此没有任何东西被添加到微任务队列中

.

**microtask queue**
**empty**

why adding setTimeout results in the expected order

现在让我们更改executorFunction以添加setTimeout

function executorFunction(num,reject) => {
        setTimeout(function() {
            if (fail) {
              reject(num);
            } else {
              resolve(num)
            }
        });
    };
}
function success(res) {
    console.log("*Success:* " + res)
}
function error(error) {
    console.log("*Error:* " + error)
}

const p1 = new Promise(executorFunction(1,error);

同样,为简洁起见,我们只使用两个承诺,第一个失败,因为我们知道原始代码中的输出将成功2然后失败1
现在我们有两个队列要考虑…… microtask和“timer” – 定时器队列的优先级低于微任务队列…即当没有运行(立即)时,JS将处理微任务队列直到它为空甚至尝试计时器队列

所以 – 我们走了

在我们的代码结束时

** empty microtask queue **                             timer queue
                                                        setTimeout(resolve(2))
                                                        setTimeout(reject(1))

处理定时器队列,我们​​得到一个微任务(拒绝:1).然后(成功,空).then(null,error)

** microtask queue **                                   timer queue
(rejected:1).then(success,error)      setTimeout(resolve(2))

哦,微任务队列中有一些东西,让我们处理它并忽略定时器队列

>它看到一个被拒绝的承诺(1),因为它有一个处理程序(原始代码中的.catch)被添加到微任务队列中

哦,让我们处理它并忽略定时器队列

** microtask queue **                                   timer queue
(rejected:1).then(success,error)      setTimeout(resolve(2))

>它看到一个被拒绝的promise(1)并且有一个onrejected处理程序调用错误
>输出错误1
> .then返回一个promise,因此没有任何东西被添加到微任务队列中

现在队列看起来像

** microtask queue **                                   timer queue
                                                        setTimeout(resolve(2))

所以,我不需要继续,因为错误1已经在第二个承诺链开始之前输出了:p1

javascript – 为什么JS承诺先打印所有解析然后拒绝第二个的更多相关文章

  1. html5 拖拽及用 js 实现拖拽功能的示例代码

    这篇文章主要介绍了html5 拖拽及用 js 实现拖拽,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. HTML5适合的情人节礼物有纪念日期功能

    这篇文章主要介绍了HTML5适合的情人节礼物有纪念日期功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. Html5原创俄罗斯方块(基于canvas)

    这篇文章主要介绍了Html5原创俄罗斯方块(基于canvas)的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  5. ios – 从NSOperationQueue获取底层dispatch_queue_t

    解决方法没有这样的事情,NSOperationQueue和dispatch_queue_t没有一一对应的关系,两个API中的排队概念是非常不同的.NSOperationQueue用于执行代码的唯一调度队列是全局并发队列的默认优先级.

  6. swift 数据类型转换 string 转换为 int, int转换为string 等等 string转换为nsmutablestring

    bytheway:刚接触swift不就,学到的东西比较浅~~,但是有问题可以在评论里说说,我每天上,一起成长~~早晚小牛长成大牛,~more牛~~~牛的立方~~gogo

  7. swift皮筋弹动发射飞机ios源码

    这是一个款采用swift实现的皮筋弹动发射飞机游戏源码,游戏源码比较详细,大家可以研究学习一下吧。

  8. 在Swift中应用Grand Central Dispatch(上

    在这两篇教程中,你会学到GCD的来龙去脉。起步libdispatch是Apple所提供的在IOS和OSX上进行并发编程的库,而GCD正是它市场化的名字。Swift中的闭包和OC中的块类似甚至于他们几乎就是可交换使用的。但OC中的块可以安全的替换成Swift中的闭包。再一次,这完全取决于GCD。QoS等级表示了提交任务的意图,使得GCD可以决定如何制定优先级。QOS_CLASS_USER_INteraCTIVE:userinteractive等级表示任务需要被立即执行以提供好的用户体验。

  9. 在Swift中应用Grand Central Dispatch 下

    通过使用dispatch_barrrier和dispatch_sync,你做到了让PhotoManager单例在读写照片时是线程安全的。还有,使用dispatch_async异步执行cpu密集型任务,从而为视图控制器初始化过程减负。幸运的是,dispatchgroups就是专为监视多个异步任务的完成情况而设计的。调度组调度组在一组任务都完成后会发出通知。在组内所有事件都完成时,GCDAPI提供了两种方式发送通知。打开PhotoManager.swift,替换downloadPhotosWithComple

  10. 【swift_1】swift基本语法及事例Demo

    语法类的文档网上比较多,我这里参考:Swift基本语法事例Demo:链接:http://pan.baidu.com/s/1jGCINCq密码:5mdk语法须知2个不需要不需要编写main函数:全局作用域中的代码会被自动当做程序的入口点(从上往下执行)不需要在每一条语句后面加上分号letradius=10你喜欢的话,也可以加上letradius=10;有一种情况必须加分号:同一行代码上有多条语句时1

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部