promise(一)为什么要使用promise

为什么要用promise?

promise是ES6中用来处理 异步操作 的。如果不使用promise,就需要使用 回调函数来处理异步操作后的结果,此时如果有 多个有顺序 的异步操作,会造成回调的嵌套,引发 回调地狱

举个例子,如果有两个异步操作(执行需要时间),分别是 砍柴烧水,我们不妨将他们定义为下面的两个函数:

// 砍柴需要时间2s, 是个异步操作
function kanChai(fn) {
    setTimeout(() => {
        fn();   
    }, 2000)
}
// 烧水需要时间1s, 是个异步操作
function shaoShui(fn) {
    setTimeout(() => {
        fn();
    }, 1000)
}

其中fn是回调函数,定义了砍柴或烧水这两个异步操作 执行完成后 要做的事情。

如果现在要求这两个异步操作必须按顺序执行,先砍柴再烧水,可不可以这么写呢?

(function func() {
	// 先砍柴
	kanChai(() => {
	     console.log("砍柴完成")
	 });
	// 后烧水
	shaoShui(() => {
	    console.log("烧水完成");
	})
})();

这么写的话,其实砍柴和烧水两个函数的执行在func函数中是同步的,两个动作会同时进行,并且由于烧水用时短,会先执行完毕输出"烧水完成"。显然并不是我们要的结果。

正确的写法应该把烧水嵌套在砍柴内:

(function func() {
    kanChai(() => {
        console.log("砍柴完成");
        shaoShui(() => {
            console.log("烧水完成");
        })
    })
})();

这样执行的结果是2s后输出"砍柴完成",接着1s后输出"烧水完成"。

相信大家很容易看出这种方式的弊端:如果有 多个有顺序的 异步操作,则会不停的嵌套,造成 回调地狱:即 砍柴完成后要做的事情(砍柴的回调) 和 烧水完成后要做的事情(烧水的回调) 被堆到了一块,造成代码可读性和可维护性极差。
在这里插入图片描述
而promise的出现,将 砍柴完成后要做的事情烧水完成后要做的事情 从代码层面上分离开来了。

怎么用promise?

我们把上面的那个例子用promise来重新写一下,不过要对两个函数修改一下,将回调函数去掉,用promise来代替。

function kanChai() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("砍柴完成");
        }, 2000)
    })
}

function shaoShui() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("烧水完成");
        }, 1000)
    })
}

在砍柴和烧水两个函数中返回了 包裹着异步代码的Promise对象,以便于我们可以调用then方法then方法会接收resolve传递的数据,对该数据进行进一步操作。

kanChai().then((data) => {
    console.log(data);
})

在只有一个异步操作时,还看不出优势。但是如果要实现先砍柴,后烧水,就可以这么写。

kanChai().then((data) => {
    console.log(data);
    return shaoShui();
}).then((data) => {
    console.log(data);
})

通过这种链式调用,即可实现2s后输出"砍柴完成",再过1s输出"烧水完成"。如果还有一些其他的异步操作(如煮饭,盛饭等)在他们之后执行,则是这是的:

kanChai().then((data) => {
    console.log(data);
    return shaoShui();
}).then((data) => {
    console.log(data);
    return zhufan();
}).then((data)=>{
	console.log(data);
	return chengfan();
}).then(...)

从这里就可以看出来promise和普通回调函数的区别:

  • 普通回调函数将"取数据"和"操作数据"两个动作封装到了一块。
  • Promise将"取数据"这样的异步动作放在了Promise内,而"操作数据"动作被放到了then方法中,实现了"取数据"和"操作数据"的解耦。

上面的代码暂时看不懂没事,只要知道使用Promise能带来的好处:将本应该在回调函数中处理的代码提取到了外面,避免了回调函数的嵌套,使得代码更可读可维护。接下来讲一下Promise到底内部做了什么。

promise原理?

通过new Promise构造器创建的promise对象是 有状态的,状态可能是

  • pending(进行中),
  • resolved(已完成,也称为fullfilled),
  • rejected(已失败)
let p = new Promise((resolve, reject) => {
  setTimeout(function () {
    resolve('11');
  }, 1000)
})

当实例化promise对象后,定时结束前,Promise对象状态为pedding。
在这里插入图片描述
一旦定时结束,Promise对象状态由pending切换为fulfilled。
在这里插入图片描述
细心的同学可能还注意到了,Promise内部除了状态,还多了个结果字符串"11"。这个结果就存了Promise中resolve要传出的值。
其实promise即承诺,意思是在 未来某一个时间点 承诺返回 数据 给你。因此Promise除了需要记录当前状态,还要记录传出去的数据。

resolve()方法

resolve方法有两个作用:

  • 将这个promise对象的状态从 pending 变为 resolved。
  • 将异步操作的结果data,作为参数传递出去。

一旦promise对象的状态从pending变成resolved,就调用then方法中的第一个回调函数。所以 调用resolve方法其实就是在调用then方法

then()方法

then方法接收的参数同样是一个函数,这个函数的作用是对异步操作成功后resolve传出的数据进行处理。
这里值得一提的是then()方法的返回值:then方法的返回值也是一个Promise对象

function kanChai() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("砍柴完成");
        }, 2000)
    })
}

let p = kanChai().then((data) => {
	console.log(data);
})

此时的p是个没有Result的Promise对象。
在这里插入图片描述
如果我们在then方法中返回一个普通字符串。

let p = kanChai().then((data) => {
  	console.log(data);
    return "你好"
})

2s过后,此时p对象的Result不再为undefined。
在这里插入图片描述
事实上,即使then()方法中返回的是"你好"字符串,内部也同样会将该字符串包装成一个Promise对象返回。
正是由于then()方法也返回Promise对象这个特性,使得我们可以链式调用.then方法。

kanChai().then((data) => {
    console.log(data);
    return shaoshui();
}).then((data) => {
    console.log(data);
})

如果直接返回一个Promise对象,不就是最开始举的那个例子吗,是不是看懂了。

其他

刚刚其实只讲了Promise中的异步代码执行成功以后的处理,如果异步代码执行失败,则会用到一个与resolve函数对应的 reject函数

let p = new Promise((resolve, reject)=>{
	resolve("执行成功的数据");
	reject("执行失败的提示")
})

then方法的第二个参数也是一个函数,这个函数用来对错误信息的处理。

p.then((data)=>{
	对data的处理...
}, (err)=>{
	对错误的处理...
})

当有多个Promise中的异步请求之间没有执行顺序时,我们可以使用Promise.all方法来包裹这些Promise。

Promise.all([
	new Promise(...),
	new Promise(...),
	...
]).then(result=>{
	console.log(result[0]);
	console.log(result[1]);
})
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值