ES2015 笔记(4) Promise

透过ES2015建立Promise对象,让你的JavaScript程序更容易阅读,更好维护


说实在一开始看到JavaScript的Promise写法

脑中浮现的想法就是"这不就是 linq 吗"

自然也不觉得陌生,了解后反而觉得这种写法很好阅读也很方便

什么是Promise,什么时候需要

会需要Promise的写法,主要原因是我们不想要让程序Hang在某一段程序,其作用就像async

在解释Promise的运行前,先看一下以下的例子

若是BuildPayList会花很久的时间,假若是数秒以上,我们就会希望用到Promise的作法

所以程序在等待BuildPayList完成前会继续往下执行

所以你会有看到finsih的消息会先被输出,然后才会回去执行 then 里面的东西

    BuildPayList(myMoney)
	//check is money is enough to pay all
	.then(CheckIsAblePayAll)

    console.log("finish");

在New Promise时,会有内建两个方法分别是resolve 跟 reject,共会有三种状态

  1. 第一个就是你new出来Promise这个对象时会呈现于pending状态
  2. 第二个就是fulfill的状态,这个就会是走到then的语法
  3. 第三个就是reject的状态,这边就会执行到catch的语法

情境如下,我们需要建立一个付账清单,然后再去检查我们身上的钱是否足以支付这个清单

如何使用Promise的机制写出易懂的程序

首先我们有一个BuildPayList的function来建立Promise对象

resolve时回传的对象为 {money, PayList [{ item, cost}] }

reject 时回传的对象为 { Success, Message}

function BuildPayList(money = 0){	
	return new Promise(function (resolve, reject){
		if (money > 0)
			resolve({money, PayList: [{item:"food", cost:100}, {item:"insurance", cost:1500} ], payLog:[]});
		else
			reject({Success: false, Message: "You don't any money to pay!"});
	});
}

接着我们再建立一个function用来检查是否身上的钱足够支付清单,这边的对象架构为上述resolve时所回传的对象

function CheckIsAblePayAll(obj){
	let tempMoney = obj.money
	for (let pay of obj.PayList){
		tempMoney-= pay.cost;
		if (tempMoney < 0 )
			throw "You don't have enough money to pay all items!";
		}
		
	return obj;
}

最后则是,若是能够支付所有清单,则实行付钱的行为,这里的参数跟CheckIsAblePayAll里用的是一样的

付完帐后,我们则把付账过程的记录跟剩下的金钱回传 {payLog [ ], RestMoney}

function PayAll(obj){
	for (let pay of obj.PayList)
	{
		obj.payLog.push(`You have ${obj.money}, spend ${pay.cost} on ${pay.item}, remaining ${obj.money - pay.cost}`);
		obj.money -= pay.cost;
	}
	return {payLog:obj.payLog, restMoney: obj.money};
}

当我们把所有的function都写完时,这时候的重头戏就是我们如何使用Promise写出易读的程序了

	let myMoney = 2000;
	BuildPayList(myMoney)
	//check is money is enough to pay all
	.then(CheckIsAblePayAll)
	.then(PayAll)
	//display all pay log
	.then((result)=> {		
		for (let log of result.payLog)
			console.log(log);
		console.log(`Finally, you have ${result.restMoney} on hand`);
	})
	.catch((error)=> console.log(error));

我们来看看Promise是怎么运行的

一开始当我们把手头上的2000元当作参数当参数调用BuildPayList(2000)时

会先得到一个Promise的对象,在执行到调用resolve或是reject时,Promise都是处于pending状态

直到判断我们手头上的现金大于0时,即会执行resolve的方法,才会由pending转为fulfilled

若是一开始money小于0,则会走向rejected,即会执行catch

当对象建立起,即开始执行第一个 then ,即为CheckIsAblePayAll

在CheckIsAblePayAll中也会检查手头的钱是否够付,若是够付(resolve),则将一开始建立的对象回传

不够付则throw excpetion,即为走向catch (reject)

在够付的情况下,执行第二个then 执行付钱的动作,最后将payLog与restMoney返回

最后一个then则是一个arrow function,负责将payLog呈现出来,并将剩下的钱输出

最后一行的catch则表式,这个Promise的对象一个接一个的then执行中,若状态变成rejected,则会执行

执行的结果如下

1. money=2000

You have 2000, spend 100 on food, remaining 1900
You have 1900, spend 1500 on insurance, remaining 400
Finally, you have 400 on hand

2. money=1000 (在执行到第一个then就会throw exception到catch了)

You don't have enough money to pay all items!

3. money=0 (连第一个then都还没执行到,在new Promise时就被引至reject了)

Object {sucess: false, Message: "You don't any money to pay!"}

看完这个好东西,你应该会等不及想要把Promise对象应用到你的JavaScript上了