Heim > Fragen und Antworten > Hauptteil
P粉6183582602023-08-22 16:14:21
今天,我可以在Node.js
中使用Promise
作为一个普通的Javascript方法。
一个简单和基本的Promise
示例(使用KISS方法):
普通的Javascript异步API代码:
function divisionAPI (number, divider, successCallback, errorCallback) { if (divider == 0) { return errorCallback( new Error("Division by zero") ) } successCallback( number / divider ) }
Promise
的Javascript异步API代码:
function divisionAPI (number, divider) { return new Promise(function (fulfilled, rejected) { if (divider == 0) { return rejected( new Error("Division by zero") ) } fulfilled( number / divider ) }) }
(我推荐访问这个优秀的来源)
此外,Promise
也可以与ES7
中的async\await
一起使用,使程序流程等待fulfilled
结果,如下所示:
function getName () { return new Promise(function (fulfilled, rejected) { var name = "John Doe"; // 在调用fulfilled()方法之前等待3000毫秒 setTimeout ( function() { fulfilled( name ) }, 3000 ) }) } async function foo () { var name = await getName(); // 等待fulfilled结果! console.log(name); // 控制台在3000毫秒后输出"John Doe" } foo() // 调用foo()方法运行代码
使用相同的代码,可以使用.then()
方法:
function getName () { return new Promise(function (fulfilled, rejected) { var name = "John Doe"; // 在调用fulfilled()方法之前等待3000毫秒 setTimeout ( function() { fulfilled( name ) }, 3000 ) }) } // 控制台在3000毫秒后输出"John Doe" getName().then(function(name){ console.log(name) })
Promise
也可以在任何基于Node.js的平台上使用,比如react-native
。
额外奖励:一种混合方法
(假设回调方法有两个参数,分别是错误和结果)
function divisionAPI (number, divider, callback) { return new Promise(function (fulfilled, rejected) { if (divider == 0) { let error = new Error("Division by zero") callback && callback( error ) return rejected( error ) } let result = number / divider callback && callback( null, result ) fulfilled( result ) }) }
上述方法可以同时响应旧式的回调和Promise用法的结果。
希望这能帮到你。
P粉6800875502023-08-22 11:07:09
承诺具有状态,它们开始时处于挂起状态,可以解决为:
返回承诺的函数不应该抛出异常,而应该返回拒绝。从返回承诺的函数中抛出异常将强制您同时使用} catch {
和 .catch
。使用承诺化的API的人们不希望承诺抛出异常。如果您不确定JS中的异步API如何工作,请首先查看此答案。
因此,创建承诺通常意味着指定它们何时解决-这意味着它们何时移动到已实现或已拒绝阶段以指示数据可用(并可使用.then
访问)。
使用支持Promise
构造函数的现代承诺实现(如原生ES6承诺):
function load() { return new Promise(function(resolve, reject) { window.onload = resolve; }); }
然后您可以这样使用生成的承诺:
load().then(function() { // 在onload之后执行操作 });
使用支持延迟(这里我们使用$q作为示例,但稍后我们还将使用jQuery)的库:
function load() { var d = $q.defer(); window.onload = function() { d.resolve(); }; return d.promise; }
或者使用类似于jQuery的API,钩住一次发生的事件:
function done() { var d = $.Deferred(); $("#myObject").once("click",function() { d.resolve(); }); return d.promise(); }
这些API相当常见,因为在JS中回调很常见。让我们看看常见情况下的onSuccess
和onFail
:
function getUserData(userId, onLoad, onFail) { …
使用支持Promise
构造函数的现代承诺实现(如原生ES6承诺):
function getUserDataAsync(userId) { return new Promise(function(resolve, reject) { getUserData(userId, resolve, reject); }); }
使用支持延迟(这里我们使用jQuery作为示例,但我们之前也使用了$q)的库:
function getUserDataAsync(userId) { var d = $.Deferred(); getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); }); return d.promise(); }
jQuery还提供了$.Deferred(fn)
形式,它的优点是允许我们编写一个非常接近new Promise(fn)
形式的表达式,如下所示:
function getUserDataAsync(userId) { return $.Deferred(function(dfrd) { getUserData(userId, dfrd.resolve, dfrd.reject); }).promise(); }
注意:这里我们利用了jQuery延迟的resolve
和reject
方法是“可分离”的事实;即它们绑定到jQuery.Deferred()的实例。并非所有库都提供此功能。
Node风格回调(nodebacks)具有特定的格式,其中回调始终是最后一个参数,其第一个参数是错误。首先手动将其转换为承诺:
getStuff("dataParam", function(err, data) { …
转换为:
function getStuffAsync(param) { return new Promise(function(resolve, reject) { getStuff(param, function(err, data) { if (err !== null) reject(err); else resolve(data); }); }); }
使用延迟,您可以执行以下操作(我们使用Q作为示例,尽管Q现在支持新语法您应该优先选择该语法):
function getStuffAsync(param) { var d = Q.defer(); getStuff(param, function(err, data) { if (err !== null) d.reject(err); else d.resolve(data); }); return d.promise; }
一般来说,您不应该手动过多地将事物转换为承诺,大多数针对Node设计的承诺库以及Node 8+中的原生承诺都具有用于将nodebacks转换为承诺的内置方法。例如
var getStuffAsync = Promise.promisify(getStuff); // Bluebird var getStuffAsync = Q.denodeify(getStuff); // Q var getStuffAsync = util.promisify(getStuff); // 原生承诺,仅限Node
这里没有黄金法则,您可以逐个将它们转换为承诺。但是,某些承诺实现允许您批量执行此操作,例如在Bluebird中,将nodeback API转换为承诺API就像这样简单:
Promise.promisifyAll(API);
或在Node中使用原生承诺:
const { promisify } = require('util'); const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)})) .reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
注意:
.then
处理程序中时,当然不需要将事物转换为承诺。从.then
处理程序返回一个承诺将使用该承诺的值解决或拒绝。从.then
处理程序中抛出异常也是良好的实践,将拒绝该承诺-这就是著名的承诺抛出安全性。onload
情况中,您应该使用addEventListener
而不是onX
。