ES6 Promises
Promise 语法
promise 相关的 语法如下所述,其中 p 是 promise 对象,resolve 是 promise 执行成功时应该调用的函数,reject 是 promise 遇到错误时应该调用的函数。
let p = new Promise(function(resolve,reject){
let workDone = true; // some time consuming work
if(workDone){
//invoke resolve function passed
resolve('success promise completed')
}
else{
reject('ERROR , work could not be completed')
}
})
示例
下面给出的示例显示了一个函数 add_positivenos_async()
,它异步地添加两个数字。 如果传递正值,则 Promise 得到解决。 如果传递负值,则 Promise 将被拒绝。
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
}
else
reject('NOT_Postive_Number_Passed')
})
return p;
}
add_positivenos_async(10, 20)
.then(successHandler) // if promise resolved
.catch(errorHandler);// if promise rejected
add_positivenos_async(-10, -20)
.then(successHandler) // if promise resolved
.catch(errorHandler);// if promise rejected
function errorHandler(err) {
console.log('Handling error', err)
}
function successHandler(result) {
console.log('Handling success', result)
}
console.log('end')
上述代码的输出将如下所述
end
Handling success 30
Handling error NOT_Postive_Number_Passed
Promise 链
当我们要一个接一个地完成一系列异步任务时,可以使用 Promises 链。 当一个 promise 依赖于另一个 promise 的结果时,promise 被链接起来。 这在下面的示例中显示
示例
在下面的示例中,add_positivenos_async()
函数异步添加两个数字,如果传递负值则拒绝。 当前异步函数调用的结果作为参数传递给后续函数调用。 注意每个 then()
方法都有一个 return
语句。
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
}
else
reject('NOT_Postive_Number_Passed')
})
return p;
}
add_positivenos_async(10,20)
.then(function(result){
console.log("first result",result)
return add_positivenos_async(result,result)
}).then(function(result){
console.log("second result",result)
return add_positivenos_async(result,result)
}).then(function(result){
console.log("third result",result)
})
console.log('end')
上述代码的输出如下所示
end
first result 30
second result 60
third result 120
下面详细讨论了Promise对象的一些常用方法
Promise.all()
此方法可用于聚合多个承诺的结果。
语法
下面提到了 promise.all()
方法的语法,其中,iterable 是一个可迭代对象。 例如。 Array。
Promise.all(iterable);
下面给出的示例执行一组异步操作 [add_positivenos_async(10,20),add_positivenos_async(30,40),add_positivenos_async(50,60)]
。 当所有操作完成后,promise 就完全解决了。
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
}
else
reject('NOT_Postive_Number_Passed')
})
return p;
}
//Promise.all(iterable)
Promise.all([add_positivenos_async(10,20),add_positivenos_async(30,40),add_positivenos_async(50,60)])
.then(function(resolveValue){
console.log(resolveValue[0])
console.log(resolveValue[1])
console.log(resolveValue[2])
console.log('all add operations done')
})
.catch(function(err){
console.log('Error',err)
})
console.log('end')
上述代码的输出将如下所述
end
30
70
110
all add operations done
promise.race()
此函数接受一组 promise 并返回第一个已完成的 promise 。
语法
下面提到了 promise.race()
函数的语法,其中,iterable 是一个可迭代对象。 例如。 Array。
Promise.race(iterable)
示例
下面给出的示例采用异步操作数组 [add_positivenos_async(10,20),add_positivenos_async(30,40)]
。
只要任何一个添加操作完成,承诺就会得到解决。 Promise 不会等待其他异步操作完成。
function add_positivenos_async(n1, n2) {
let p = new Promise(function (resolve, reject) {
if (n1 >= 0 && n2 >= 0) {
//do some complex time consuming work
resolve(n1 + n2)
} else
reject('NOT_Postive_Number_Passed')
})
return p;
}
//Promise.race(iterable)
Promise.race([add_positivenos_async(10,20),add_positivenos_async(30,40)])
.then(function(resolveValue){
console.log('one of them is done')
console.log(resolveValue)
}).catch(function(err){
console.log("Error",err)
})
console.log('end')
上述代码的输出将如下所述
end
one of them is done
30
Promises 是一种在 JavaScript 中实现异步编程的简洁方式(ES6 新特性)。 在承诺之前,回调用于实现异步编程。 让我们首先了解什么是异步编程及其使用回调的实现。
了解回调
一个函数可以作为参数传递给另一个函数。 这种机制称为回调。 回调在事件中会有帮助。
下面的例子将帮助我们更好地理解这个概念。
function notifyAll(fnSms, fnEmail) {
console.log('starting notification process');
fnSms();
fnEmail();
}
notifyAll(function() {
console.log("Sms send ..");
},
function() {
console.log("email send ..");
});
console.log("End of script");
// 最后执行或被其他方法阻塞
在上面显示的 notifyAll()
方法中,通过发送 SMS 和发送电子邮件进行通知。 因此,notifyAll
方法的调用者必须传递两个函数作为参数。 每个函数承担单一职责,例如发送 SMS 和发送电子邮件。
成功执行上述代码后会显示以下输出。
starting notification process
Sms send ..
Email send ..
End of script
在上面提到的代码中,函数调用是同步的。 这意味着 UI 线程将等待完成整个通知过程。 同步调用变成阻塞调用。 现在让我们了解非阻塞或异步调用。
了解异步回调
考虑上面的例子。
要启用该脚本,请执行对 notifyAll()
方法的异步或非阻塞调用。 我们将使用 JavaScript 的 setTimeout()
方法。 默认情况下,此方法是异步的。
setTimeout()
方法有两个参数 -
一个回调函数。
调用方法之前的秒数。
在这种情况下,通知进程已超时。 因此,将需要两秒钟的延迟,由代码设置。 notifyAll()
将被调用,主线程继续执行其他方法。 因此,通知进程不会阻塞主 JavaScript 线程。
function notifyAll(fnSms, fnEmail) {
setTimeout(function() {
console.log('starting notification process');
fnSms();
fnEmail();
}, 2000);
}
notifyAll(function() {
console.log("Sms send ..");
},
function() {
console.log("email send ..");
});
console.log("End of script"); // 先执行或不被其他人阻止
成功执行上述代码后会显示以下输出。
End of script
starting notification process
Sms send ..
Email send ..
如果有多个回调,代码看起来会很吓人。
setTimeout(function() {
console.log("one");
setTimeout(function() {
console.log("two");
setTimeout(function() {
console.log("three");
}, 1000);
}, 1000);
}, 1000);
ES6 通过引入 promise 的概念来拯救你。 Promises 是“延续事件”,它们可以帮助您以更简洁的代码风格一起执行多个异步操作。
示例
让我们用一个例子来理解这一点。 以下是相同的语法。
var promise = new Promise(function(resolve , reject) {
// do a thing, possibly async , then..
if(/*everthing turned out fine */) resolve("stuff worked");
else
reject(Error("It broke"));
});
return promise;
实现 promise 的第一步是创建一个使用承诺的方法。 假设在这个例子中,getSum()
方法是异步的,即它的操作不应该阻止其他方法的执行。 此操作一完成,稍后就会通知调用者。
以下示例(第 1 步)声明了一个 Promise 对象“var promise”。 Promise 构造函数首先接受函数以成功完成工作,然后再接受一次以防发生错误。
promise通过resolve回调返回计算结果并传入结果,即n1+n2
步骤 1 - 解决(n1 + n2);
如果 getSum() 遇到错误或意外情况,它将调用 Promise 中的 reject 回调方法并将错误信息传递给调用方。
步骤 2 - reject(Error("Negatives not supported"));
以下代码(第 1 步)中给出了方法实现。
function getSum(n1, n2) {
varisAnyNegative = function() {
return n1 < 0 || n2 < 0;
}
var promise = new Promise(function(resolve, reject) {
if (isAnyNegative()) {
reject(Error("Negatives not supported"));
}
resolve(n1 + n2)
});
return promise;
}
第二步详细说明了调用者的实现(STEP 2)。
调用者应使用“then”方法,该方法采用两个回调方法——第一个用于成功,第二个用于失败。 每个方法都有一个参数,如以下代码所示。
getSum(5, 6)
.then(function (result) {
console.log(result);
},
function (error) {
console.log(error);
});
成功执行上述代码后会显示以下输出。
11
由于 getSum()
的返回类型是 Promise,我们实际上可以有多个“then”语句。 第一个 'then' 将有一个 return 语句。
getSum(5, 6)
.then(function(result) {
console.log(result);
returngetSum(10, 20);
// this returns another promise
},
function(error) {
console.log(error);
})
.then(function(result) {
console.log(result);
},
function(error) {
console.log(error);
});
成功执行上述代码后会显示以下输出。
11
30
以下示例使用 getSum()
方法发出三个 then()
调用。
function getSum(n1, n2) {
varisAnyNegative = function() {
return n1 < 0 || n2 < 0;
}
var promise = new Promise(function(resolve, reject) {
if (isAnyNegative()) {
reject(Error("Negatives not supported"));
}
resolve(n1 + n2);
});
return promise;
}
getSum(5, 6)
.then(function(result) {
console.log(result);
returngetSum(10, 20);
//this returns another Promise
},
function(error) {
console.log(error);
})
.then(function(result) {
console.log(result);
returngetSum(30, 40);
//this returns another Promise
},
function(error) {
console.log(error);
})
.then(function(result) {
console.log(result);
},
function(error) {
console.log(error);
});
console.log("End of script ");
成功执行上述代码后会显示以下输出。
该程序首先显示“脚本结束”,然后逐个显示调用 getSum()
方法的结果。
End of script
11
30
70
这表明 getSum()
是以异步方式或非阻塞方式调用的。 Promise 提供了一种简洁明了的方式来处理回调。