资讯专栏INFORMATION COLUMN

ECMAScript 6入门Promise对象

ingood / 398人阅读

摘要:对象的状态不受外界影响。如果改变已经发生了,你再对对象添加回调函数,也会立即得到这个结果。会等中的对象全部执行完后将数组传入回调函数中与不同的是只要之中有一个实例率先改变状态,的状态就跟着改变。

Promise对象

刚学习完,有点粗略印象。整理记录一下以便后续学习补充,加深理解。

Promise是什么

Promise是构造函数,可以通过new来生成Promise对象。

Promise有什么用

目前我的感受是:更加方便来操作异步流程,更加明确直观的控制事件的流程以及可以链式调用

Promise特点

摘自ES6入门

Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
通过几个简单例子理解它

通过new构造一个简单的Promise对象

let p = new Promise((resolve, reject) => {});

传入的两个参数是用来控制Promise对象的状态,我们打印一下p看一下它的状态:
Promise {__proto__: Promise[[PromiseStatus]]: "pending"[[PromiseValue]]: undefined这个就是初始状态pending
而resolve,reject可以控制Promise的状态

//resolve()
let p = new Promise((resolve, reject) => resolve("123")); //Promise {: "123"}
//reject()
let p = new Promise((resolve, reject) => reject("123")); //reject()后是返回一个失败状态的Promise,不需要用catch来捕获不写catch会报错
p.catch(data => console.log(data));    
console.log(p);    //Promise {: "123"}   123

提到了catch那就有还有一个then
说一直白点:then(f1, f2)可以填入两个函数参数,一个参数就是将resolve中参数代入f1来执行,第二个参数将reject中参数代入f2来执行;第二个参数可以用catch来代替,并且它更加强大,catch能捕获then()中的报错

let p = new Promise((resolve, reject) => {
    
    let n = Math.ceil(Math.random() * 10);
    n > 5 ? resolve(n) : reject(n);
});
p.then(
    data => console.log(data),
    data => console.log(data),
)

用catch代替,并捕获then的错误

let p = new Promise((resolve, reject) => {
    
    resolve("yes")
});
p.then(
    data => {console.log(data),console.log(a)}

).catch(data => console.log(data));
//yes
//ReferenceError: a is not defined

因为then处理后返回的还是Promise对象,这样方便链式调用,then中都没有return,怎么会有Promise对象的呢?

then或catch即使未显式指定返回值, 它们也总是自动包装一个新的fulfilled状态的promise对象。

我们打印一下会发现:Promise {: undefined}
那么我们可以显示的return一个Promise对象看看,

let p = new Promise((resolve, reject) => resolve("yes"));
p.then(data => Promise.resolve("第二个Promise")).then(data => console.log(data));   //第二个Promise

可以看到p.then(data => Promise.resolve("第二个Promise"))返回Promise对象是Promise {: "第二个Promise"}并且将value值作为参数传入到第二个then中来执行

Promise.resolve(value | promise | thenable)创建Promise对象
第一参数空或者原始值,创建后的Promise对象状态直接为resolved状态

Promise.resolve("f")
// 等价于
new Promise(resolve => resolve("f"))

第二值得注意的是具有then方法的对象

let thenable = {
    then :(resolve, reject) => resolve("thenable")
}

let p = Promise.resolve(thenable);
console.log(p);    

Promise对象状态由->
第三参数为实例化的Promise对象,

let p1 = new Promise((resolve, reject) => false);
let p = Promise.resolve(p1);
console.log(p);

p状态和p1状态一致的

Promise.reject(value)创建Promise对象
与resolve不同的是:直接将value原样作为参数传入

const thenable = {
  then(resolve, reject) {
    reject("出错了");
  }
};

Promise.reject(thenable)
.catch(e => {
  console.log(e === thenable)
})

catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。

Promise.all
将多个 Promise 实例,包装成一个新的 Promise 实例;const p = Promise.all([p1, p2, p3]);

(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。(2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

会等all中的对象全部执行完后将数组传入回调函数then中

let p = new Promise((resolve, reject) => setTimeout(() => resolve("p"),1000));
let p1 = new Promise((resolve, reject) => setTimeout(() => resolve("p2"),2000));
let p2 = new Promise((resolve, reject) => setTimeout(() => resolve("p3"),3000));
Promise.all([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));    // ["p", "p2", "p2"]
let p = new Promise((resolve, reject) => resolve("p"));
let p1 = new Promise((resolve, reject) => reject("p2"));
let p2 = new Promise((resolve, reject) => resolve("p2"));
Promise.all([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));   //p2

Promise.race
与all不同的是:只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

let p = new Promise((resolve, reject) => setTimeout(() => resolve("p"),1000));
let p1 = new Promise((resolve, reject) => setTimeout(() => resolve("p2"),2000));
let p2 = new Promise((resolve, reject) => setTimeout(() => resolve("p3"),3000));
Promise.race([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));   //p

Promise对象的回调函数与setTimeout的顺序问题

An event loop has one or more task queues. A task queue is an ordered list of tasks, which are algorithms that are responsible for such work as: events, parsing, callbacks, using a resource, reacting to DOM manipulation…Each event loop has a microtask queue. A microtask is a task that is originally to be queued on the microtask queue rather than a task queue.
浏览器(或宿主环境) 遵循队列先进先出原则, 依次遍历macrotask queue中的每一个task, 不过每执行一个macrotask, 并不是立即就执行下一个, 而是执行一遍microtask queue中的任务, 然后切换GUI线程重新渲染或垃圾回收等.
Event Loop (事件循环)拥有如下两种队列
macrotask queue, 指的是宏任务队列, 包括rendering, script(页面脚本), 鼠标, 键盘, 网络请求等事件触发, setTimeout, setInterval, setImmediate(node)等等.
microtask queue, 指的是微任务队列, 用于在浏览器重新渲染前执行, 包含Promise, process.nextTick(node), Object.observe, MutationObserver回调等.
process.nextTick > promise.then > setTimeout ? setImmediate
setTimeout(function () {
  console.log("three");
}, 0);

Promise.resolve().then(function () {
  console.log("two");
});

console.log("one");

// one
// two
// three

上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log("one")则是立即执行,因此最先输出。

setTimeout(function() {
  console.log(4)
}, 0);
new Promise(function(resolve) {
  console.log(1);
  for (var i = 0; i < 10000; i++) {
    i == 9999 && resolve()
  }
  console.log(2);
}).then(function() {
  console.log(5)
});
console.log(3);  //1 2 3 5 4 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98640.html

相关文章

  • 谈谈ES6前后的异步编程

    摘要:回调函数这是异步编程最基本的方法。对象对象是工作组提出的一种规范,目的是为异步编程提供统一接口。诞生后,出现了函数,它将异步编程带入了一个全新的阶段。 更多详情点击http://blog.zhangbing.club/Ja... Javascript 语言的执行环境是单线程的,如果没有异步编程,根本没法用,非卡死不可。 为了解决这个问题,Javascript语言将任务的执行模式分成两种...

    fizz 评论0 收藏0
  • 实现 JavaScript 异步方法 Promise.all

    摘要:本次的任务假如。。。。。引擎发生了重大故障,方法变成了,为了拯救世界,需要开发一个模块来解决此问题。实现首先要知道是什么是对异步编程的一种抽象。数组中任何一个为的话,则整个调用会立即终止,并返回一个的新的对象。 本次的任务 假如。。。。。 JavaScript v8 引擎发生了重大故障,Promise.all 方法变成了 undefined ,为了拯救 JavaScript 世界,需要...

    mushang 评论0 收藏0
  • ES6-7

    摘要:的翻译文档由的维护很多人说,阮老师已经有一本关于的书了入门,觉得看看这本书就足够了。前端的异步解决方案之和异步编程模式在前端开发过程中,显得越来越重要。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。 JavaScript Promise 迷你书(中文版) 超详细介绍promise的gitbook,看完再不会promise...... 本书的目的是以目前还在制定中的ECMASc...

    mudiyouyou 评论0 收藏0
  • 前端 api 请求缓存方案

    摘要:而缓存系统数据,我采用另外的方案。调用方式第二次调用取得先前的方案二缓存方案一本身是不足的。当前缓存中没有该对进行操作在请求回来后,如果出现问题,把从中删除以避免第二次请求继续出错返回该代码避免了方案一的同一时间多次请求的问题。 在开发 web 应用程序时,性能都是必不可少的话题。对于webpack打包的单页面应用程序而言,我们可以采用很多方式来对性能进行优化,比方说 tree-sha...

    Binguner 评论0 收藏0
  • 前端培训-初级阶段(13、18)

    摘要:年月欧洲计算机制造商协会发表了标准,它是的一个扩延,它也被称为年月首版年月日截止发布日期,的官方名称是,国际意在更频繁地发布包含小规模增量更新的新版本,下一版本将于年发布,命名为。 前端最基础的就是 HTML+CSS+Javascript。掌握了这三门技术就算入门,但也仅仅是入门,现在前端开发的定义已经远远不止这些。前端小课堂(HTML/CSS/JS),本着提升技术水平,打牢基础知识的...

    YorkChen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<