如果需要执行一段异步代码,js有以下几种方案:
回调函数
setTimeout(function(){
setTimeout(function(){
setTimeout(function(){
......
})
})
})
有一些问题:
- 层层嵌套,代码难看,不优雅
- try{}cattch()难捕获异常
- 不能return
事件监听
发布/订阅
Promise
- Promise是一个类,类的构造函数接收一个task任务函数,该函数接收两个JavaScript引擎提供的两个参数resolve, reject
- 立即执行传入的task函数
- 如果操作(一般是异步操作)成功,调用resolve方法,并把异步的结果传入,如果传入的是一个promise,则自己的状态无效,传入的promise的状态决定了该promise的状态,如果传入的不是一个promise,resolve方法会把等待状态变成成功状态(pending -> resolved);如果操作(一般是异步操作)失败,调用reject方法,并把异步的结果传入,reject方法会把等待状态变成失败状态(pending -> rejected)。
- then方法指定回调函数,接收两个回调函数resolve, reject。当状态从pengding->resolved时,执行resolve,如果resolve的结果是一个promise,这是后面一个回调函数会等待该promise完成后执行;当状态从pengding->rejected时,执行reject。
- then方法返回一个新的Promise实例(不是原来的Promise),因此可以链式调用。
下面是模拟ES6,自己代码代码实现Promise:
function Promise(task) {
var t = this;
t.value;
t.statues = "pending";
t.resolveCallbacks = [];
t.rejectCallbacks = [];
function resolve(value){
if(value instanceof Promise){
value.then(resolve, reject);
}else{
t.statues = "fufilled";
t.value = value;
t.resolveCallbacks.forEach(item=>item(value));
}
}
function reject(value){
if(value instanceof Promise){
value.then(resolve, reject);
}else{
t.statues = "rejected";
t.value = value;
t.rejectCallbacks.forEach(item=>item(value));
}
}
try{
task(resolve, reject);
}catch(e){
reject(e);
}
}
function resolvePromise(x, resolve, reject){
if(x instanceof Promise){
if(x.statues == "fufilled"){
resolve(x.value);
}else if(x.statues == "rejected"){
reject(x.value);
}else{
x.then(function (y) {
resolvePromise(y, resolve, reject);
}, reject)
}
}else if(x != null && (typeof x == "object" || typeof x == "function")){
let then = x.then;
if(typeof then == "function"){
x.then.call(x, function (y2) {
resolvePromise(y2, resolve, reject);
}, reject)
}
}else{
resolve(x);
}
}
Promise.prototype = {
then: function (resolveCall, rejectCall) {
let t = this;
let promise2;
resolveCall = typeof resolveCall == "function" ? resolveCall : function () {
return t.value;
}
rejectCall = typeof rejectCall == "function" ? rejectCall : function () {
return t.value;
}
if(t.statues == "fufilled"){
promise2 = new Promise(function (resolve, reject) {
let x = resolveCall(t.value);
resolvePromise(x, resolve, reject);
})
}else if(t.statues == "rejected"){
promise2 = new Promise(function (resolve, reject) {
let x = rejectCall(t.value);
resolvePromise(x, resolve, reject);
})
}else if(t.statues == "pending"){
promise2 = new Promise(function (resolve, reject) {
t.resolveCallbacks.push(function () {
resolvePromise(resolveCall(t.value), resolve, reject);
});
t.rejectCallbacks.push(function () {
resolvePromise(rejectCall(t.value), resolve, reject);
});
})
}
return promise2;
}
}
// 快捷方法
Promise.resolve = function (value) {
return new Promise(function(resolve, reject){
resolve(value);
});
}
Promise.reject = function (value) {
return new Promise(function(resolve, reject){
reject(value);
});
}
// 所有成功resolve,否则reject
Promise.all = function (promises) {
if(!Array.isArray(promises)){
return TypeError("参数类型错误");
}
return new Promise(function (resolve, reject) {
let result = [];
let index = 0;
if(promises.length > 0){
for(let i = 0; i<promises.length; i++){
promises[i].then(function (value) {
index++;
result[i] = value;
if(index == promises.length){
resolve(result);
}
}, function (value) {
reject(value);
})
}
}
})
}
// 竞速,谁跑得快先返回谁
Promise.race = function (promises) {
if(!Array.isArray(promises)){
return TypeError("参数类型错误");
}
return new Promise(function (resolve, reject) {
if(promises.length > 0){
for(let i = 0; i<promises.length; i++){
promises[i].then(function (value) {
resolve(value);
}, function (value) {
reject(value);
})
}
}
})
}
module.exports = Promise;
Generator
- Generator可以暂停函数执行,返回任意表达式的值。
- Generator函数有两个特征,一是,function关键字和函数名之间有个*号,二是,函数体内部使用yield表达式。
- 调用Generator并不执行,返回的是遍历器对象(Iterator)。调用Iterator的next方法后,函数内部指针从函数头部或者上一次停下来的地方开始执行,直到遇到下一个yield表达式。
- 遇到yield表达式,next函数返回一个对象形如{value: , done: false|true}形式,表达式的value值是yield后面的表达式值或者最后的return值,如果没有return,函数执行完,value值就是undefined。yield表达式的返回值是next函数的传入值或者undefined。
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}
var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }
for...of循环
for...of循环自动遍历Generator函数生成的Iterator对象,不需要使用next()。
另外,也可以使用拓展运算符(...)、解构赋值,Array.from方法内部调用的,都是遍历器接口。因此:
function* numbers () {
yield 1
yield 2
return 3
yield 4
}
// 扩展运算符
[...numbers()] // [1, 2]
// Array.from 方法
Array.from(numbers()) // [1, 2]
// 解构赋值
let [x, y] = numbers();
x // 1
y // 2
// for...of 循环
for (let n of numbers()) {
console.log(n)
}
// 1
// 2
async
- async函数是Generator函数的语法糖。
- async函数返回一个Promise对象
参考:
网友评论