Promise結合reduce構建順序執行隊列

    Promise是一個解決函數異步執行的對象,有了這個對象,我們可以構造異步執行的操作。Promise對象可以通過鏈式調用的方式進行異步操作,語法如下:

    

    如下代碼,是一個簡單的異步方法。

new Promise((resolve,reject)=>{
	console.log("promise-> hello,world.this is promise. "+new Date());
	setTimeout(()=>{
		resolve("hello,world.this is promise. "+new Date());
	},1000);
}).then((value)=>{
	console.log("then   -> "+value);
});

    運行這段代碼,得到結果如下所示:

     

    通過Proimse我們很好的構建了一個異步操作,then中的函數始終都會在resolve()執行之後纔開始執行。resolve()可以攜帶參數,這個參數到了then裏面,就可以通過回調函數中的參數獲取了,如題所示的value值,就是通過resolve(args)傳遞過來的。 

    另外,這裏還有一個reject函數,就是當Promise內部執行出現異常,我們纔會調用。這時候,一般then是不會執行的,這裏如果要在reject後,繼續執行then中的內容,我們需要在then中增加一個reject的函數處理。

new Promise((resolve,reject)=>{
	console.log("promise-> hello,world.this is promise. "+new Date());
	setTimeout(()=>{
		reject("hello,world.this is promise. "+new Date());
	},1000);
}).then((value)=>{
	console.log("resolve-> "+value);
},(value)=>{
	console.log("reject -> "+value);
});

    執行結果如下:

     

    一般情況下,爲了簡單,Promise只用來做異步處理,我們都不處理reject的情況,所以Promise寫起來會很簡單。比如:

new Promise(resolve=>{
	console.log("promise-> hello,world.this is promise. "+new Date());
	setTimeout(()=>{
		resolve("hello,world.this is promise. "+new Date());
	},1000);
}).then(value=>{
	console.log("resolve-> "+value);
});

    以上示例,從直觀上感受到了Promise的強大,我們再也不用通過函數嵌套回調的方式來做異步操作了。如下所示的異步回調方法,一層套一層:

setTimeout(function(){
    //todo
    setTimeout(function(){
        //todo
        setTimeout(function(){
            //todo
        },1000);
    },1000);
},1000);

    嵌套回調,容易造成callback hell,Promise的then中,可以繼續返回新的Promise,這樣,可以構建一個簡單的異步回調。而且寫法更直觀,更易於理解:

new Promise(resolve=>{
	console.log("promise 1");
	setTimeout(()=>{
		resolve();
	},1000);
}).then(()=>{
	return new Promise(resolve=>{
		console.log("promise 2");
		setTimeout(()=>{
			resolve();
		},1000);
	});
}).then(()=>{
	return new Promise(resolve=>{
		console.log("promise 3");
		setTimeout(()=>{
			resolve();
		},1000);
	});
});

    Promise除了以上的用法,還可以有Promise.all().then()的用法,all()表示所有的操作均執行完成,再執行then()中的方法。而all()中的函數,不是順序執行,而是同時執行。

const createPromise = (id) => 
	new Promise(resolve=>
		setTimeout(()=>{
			console.log("promise->"+id+":"+new Date());
			resolve();
		},1000)
	)
var tasks = [createPromise(1),createPromise(2),createPromise(3)];
console.log(tasks);
Promise.all(tasks).then(()=>console.log("all done."));

    運行結果:

     

    從運行結果看來,他們幾乎是同一時刻,這種異步,雖然最終都會全部執行完成,再執行then()中的代碼,但是all()中的函數並沒有順序執行。如果希望then()之前的函數都是順序執行的,可以考慮通過reduce函數來實現。這裏會比較難以理解。

const createPromise = (id) => () => 
	new Promise(resolve=>
		setTimeout(()=>{
			console.log("promise->"+id+":"+new Date());
			resolve();
		},1000)
	)
var tasks = [createPromise(1),createPromise(2),createPromise(3)];
console.log(tasks);
var doTask = tasks.reduce((prev,next)=>prev.then(()=>next()),Promise.resolve());
doTask.then(()=>console.log("all done."));

    這裏需要注意的是,我們的createPromise函數,不再返回的是Promise對象,而是一個函數,函數裏面再返回Promise對象。運行我們的代碼,截圖如下:

     

    可以看到,這裏三個函數是按照順序執行的,並沒有同時執行,等到全部執行完成,最後執行then()中的方法。其實這種reduce寫法,就回到了我們前面提到的Promise().then().then().then()的寫法, 只不過使用reduce代碼更簡潔了,我們需要注意的是reduce()的數組是一個Function的數組,而不是Promise的數組。另外,reduce()方法的第二個參數,他是一個初始值,在這裏就是Promise.resolve(),他表示一個動作已經執行完成,可以進行下一個動作了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章