承诺(Promises)
Promises是一种在JavaScript中实现异步编程的简洁方法(ES6新功能)。 在承诺之前,Callbacks用于实现异步编程。 让我们首先了解异步编程及其实现,使用Callbacks。
了解回调
函数可以作为参数传递给另一个函数。 这种机制被称为Callback 。 回调对事件有帮助。
以下示例将帮助我们更好地理解这一概念。
<script>
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");
//executes last or blocked by other methods
</script>
在上面显示的notifyAll()方法中,通过发送SMS和发送电子邮件来进行通知。 因此,notifyAll方法的调用者必须传递两个函数作为参数。 每个功能都承担一项责任,如发送短信和发送电子邮件。
成功执行上述代码后,将显示以下输出。
starting notification process
Sms send ..
Email send ..
End of script
在上面提到的代码中,函数调用是同步的。 这意味着UI线程将等待完成整个通知过程。 同步调用成为阻塞调用。 让我们现在了解非阻塞或异步调用。
了解AsyncCallback
考虑上面的例子。
要启用脚本,请对notifyAll()方法执行异步或非阻塞调用。 我们将使用JavaScript的setTimeout()方法。 默认情况下,此方法是异步的。
setTimeout()方法有两个参数 -
回调函数。
调用方法之前的秒数。
在这种情况下,通知进程已包含超时。 因此,代码设置需要两秒钟的延迟。 将调用notifyAll()并且主线程继续执行其他方法。 因此,通知过程不会阻止主JavaScript线程。
<script>
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"); //executes first or not blocked by others
</script>
成功执行上述代码后,将显示以下输出。
End of script
starting notification process
Sms send ..
Email send ..
在多个回调的情况下,代码看起来很可怕。
<script>
setTimeout(function() {
console.log("one");
setTimeout(function() {
console.log("two");
setTimeout(function() {
console.log("three");
}, 1000);
}, 1000);
}, 1000);
</script>
ES6通过引入承诺的概念来帮助您。 Promise是“Continuation events”,它们可以帮助您以更清晰的代码风格一起执行多个异步操作。
例子 (Example)
让我们通过一个例子来理解这一点。 以下是相同的语法。
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;
// Give this to someone
实现承诺的第一步是创建一个使用承诺的方法。 让我们说在这个例子中, getSum()方法是异步的,即它的操作不应该阻止其他方法的执行。 一旦此操作完成,它将在稍后通知呼叫者。
以下示例(步骤1)声明了Promise对象'var promise'。 Promise构造函数首先将函数用于成功完成工作,另一个函数用于发生错误。
promise通过使用resolve回调并传入结果返回计算结果,即n1 + n2
Step 1 - 解析(n1 + n2);
如果getSum()遇到错误或意外情况,它将调用Promise中的拒绝回调方法并将错误信息传递给调用者。
Step 2 - 拒绝(错误(“不支持否定”));
方法实现在以下代码中给出(步骤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;
}
第二步详细说明了调用者的实现(步骤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()调用。
<script>
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 ");
</script>
成功执行上述代码后,将显示以下输出。
程序首先显示“脚本结束”,然后逐个调用getSum()方法。
End of script
11
30
70
这表明以异步样式或非阻塞样式调用getSum()。 Promise为处理回调提供了一种干净利落的方式。