ES6原生提供了Promise对象,高版本的nodejs可以直接使用,服务器端的开发中借住babel工具也可以使用,但是如果直接用到浏览器中,兼容性还是个问题。试下了最新的firefox和chorme浏览器都支持了,为了安全还是老老实实用jquery提供的Deferred对象吧。Promise能实现的功能$.Deferred也能实现。

原生Promise

废话就不多说了,直接上api:

  • Promise.resolve()
  • Promise.reject()
  • Promise.all()
  • Promise.then()
  • Promise.catch()
  • Promise.race() // jQuery.Deferred没找到对应的

jQuery.Deferred

对应的api有:

  • deferred.resolve() => Promise.resolve()
  • deferred.reject() => Promise.reject()
  • jQuery.when() => Promise.all()
  • deferred.then() => Promise.then()
  • deferred.fail() => Promise.catch()

对比deferred.resolve和Promise.resolve的例子

两者resolve和then的用法都一样

原生Promise

1
2
3
4
5
6
7
8
9
10
11
12
var wait = function () {
return new Promise((resolve, reject) => {
var task = () => {
resolve('done');
}
setTimeout(task, 5000);
});
}

wait().then((value) => {
console.log(value);
});

jQuery版

1
2
3
4
5
6
7
8
9
10
11
12
var wait = function () {
return $.Deferred((deferred) => {
var task = () => {
deferred.resolve('done');
}
setTimeout(task, 5000);
}).promise();
}

wait().then((value) => {
console.log(value);
});

对比deferred.fail和Promise.catch的例子

两个用法差不多

原生Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var wait = function () {
return new Promise((resolve, reject) => {
reject('error');
});
}

wait().then((value) => {
// success
}).catch ((error) => {
console.log(error)
});

// 也可以这样
wait().then((value) => {
// success
}, (error) => {
console.log(error)
});

jQuery版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var wait = function () {
return $.Deferred((deferred) => {
deferred.reject('error');
}).promise();
}

wait().then((value) => {
// success
}).fail((error) => {
console.log(error);
});

// 也可以这样
wait().then((value) => {
// success
}, (error) => {
console.log(error)
});

对比Promise.all和jQuery.when的例子

这两个区别是传入参数和返回值都不同,jQuery.when参数为单个deferred函数jQuery.when(deferred1, deferred2, deferred3);Promise.all参数为promise数组,Promise.all([promise1, promise2, promise3])。
Promise返回结果为数组,$.when返回结果和参数对应。

原生Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var promise1 = new Promise((resolve) => {
setTimeout(() => {
resolve("promise1");
}, 2000);
});

var promise2 = new Promise( (resolve) => {
setTimeout(() => {
resolve("promise2");
}, 1000);
});

Promise.all([promise1, promise2]).then((result) => {
console.log(result); // ['promise1', 'promise2']
});

jQuery版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var deferred1 = $.Deferred((deferred) => {
setTimeout(() => {
deferred.resolve("deferred1");
}, 2000);
});

var deferred2 = $.Deferred( (deferred) => {
setTimeout(() => {
deferred.resolve("deferred2");
}, 1000);
});

$.when.(deferred1, deferred2).then((result1, result2) => {
console.log(result1, result2);
});

实际开发中特殊情况填坑

根据在实际开发的经验,参数为[promise1, promise2, promise3]这种方式的更方便,某些情况$.when实现起来很悲剧。思考下面的多文件上传时$.Deferred怎么实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// file input上传的多个文件
var files = [1, 2, 3];
var handleUpload = (file) => {
return new Promise((resolve, reject) => {
// ajax上传文件到服务器
setTimeout(() => {
resolve(file+" file uploaded");
}, 1000);
});

}
// 组装成数组
var promiseArr = Array.prototype.slice.call(files, 0).map((file) => {
return handleUpload(file);
});

Promise.all(promiseArr).then((allFiles) => {
// 要用到上传成功后的所有文件
console.log(allFiles); // ["1 file uploaded", "2 file uploaded", "3 file uploaded"]
}).catch (function (err) {
console.log(err);
});

用$.Deferred也不麻烦,$.Deferred版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 写的都是假数据
// file input上传的多个文件
var files = [1, 2, 3];
var handleUpload = (file) => {
return $.Deferred((deferred) => {
// ajax上传到服务器
setTimeout(() => {
deferred.resolve(file+" file uploaded");
}, 1000);
}).promise();

}

// 组装成数组
var promiseArr = Array.prototype.slice.call(files, 0).map((file) => {
return handleUpload(file);
});

$.when.apply($, promiseArr).then(function() { // 这里不能写箭头函数了,写了arguments is not defined
// 要用到上传成功后的所有文件
var allFiles = Array.prototype.slice.call(arguments);
console.log(allFiles); // ["1 file uploaded", "2 file uploaded", "3 file uploaded"]
}).fail (function (err) {
console.log(err);
});

相关链接

jQuery Deferred 文档
阮老师的 jQuery的deferred对象详解