如何修复我的代码回调恐怖
How to fix my code callback horror
我正在尝试创建一个通知应用程序,首先是我的代码:
function sendNotification(messageUser, messageText, messageDepartment, messageTopic, userIDs) {
var userAndroid = [];
var userIOS = [];
var userDevice;
console.log(userIDs);
for (var i = 0; i < userIDs.length; i++) {
searchRegisterDevices(userIDs[i], function(result) {
if (result) {
for (var j = 0; j < result.length; j++) {
userDevice = {platform: result[j].platform, token: result[j].token};
if (userDevice.platform == 'android') {
userAndroid.push(userDevice);
} else {
userIOS.push(userDevice);
}
}
} else {
console.log("ERROR");
}
});
}
console.log(userAndroid);
if (userAndroid.length > 0) {
}
我的问题是,当我 "for looping" 收集我的设备时,我的代码继续发送部分并失败,因为 userAndroid 是空的。正如他们所说,我该怎么做才能解决这个回调地狱?我需要等到我的 for 循环完成,然后继续发送消息。如有任何帮助,我们将不胜感激!
这里的问题是您在 for 循环中执行异步请求,而不处理异步。您正在混合同步 for
循环和(大概)异步 searchRegisterDevices
。您的循环变量将继续增加,直到达到极限。所以,当你的回调函数从事件堆栈中弹出时,userIDs[i]
的值是 userIDs[userIDs.length]
,感谢 lexical scoping of javascript variables
这里你需要做的是这三者之一patterns:
使用 IIFE 创建您自己的函数闭包
var j = 10;
for (var i = 0; i < j; i++) {
(function(cntr) {
// here the value of i was passed into as the argument cntr
// and will be captured in this function closure so each
// iteration of the loop can have it's own value
asychronousProcess(function() {
console.log(cntr);
});
})(i);
}
创建或修改外部函数并将变量传递给它
如果您可以修改 asychronousProcess() 函数,那么您可以只在其中传递值,然后让 asychronousProcess() 函数 cntr 像这样返回回调:
var j = 10;
for (var i = 0; i < j; i++) {
asychronousProcess(i, function(cntr) {
console.log(cntr);
});
}
使用 ES6 让
如果你有一个 Javascript 完全支持 ES6 的执行环境,你可以像这样在 for 循环中使用 let:
const j = 10;
for (let i = 0; i < j; i++) {
asychronousProcess(function() {
console.log(i);
});
}
这里当然是asychronousProcess
代表你的searchRegisterDevices
服务调用。
以下是我使用 babel
和更新的 JS 语法的方法:
import rfpify from 'rfpify';
const findDevice = rfpify(searchRegisteredDevices);
async function sendNotification({message, toUserIDs}) {
let devices = await Promise.all(toUserIDs.map(id=>findDevice(id)));
devices = devices.map( ({platform,token}) => { return {platform,token} } );
const androidUsers = devices.filter(d => d && d.platform == 'android');
const iOSUsers = devices.filter(d => d && d.platform != 'android');
return {message, androidUsers, iOSUsers};
}
设置babel
和rfpify
:npm i -S rfpify; npm i -D babel-cli babel-preset-latest babel-plugin-transform-runtime
。创建代码所在的 src
和 lib
用于输出程序,您 运行 和 node
。将其放入 .babelrc: { "presets": [ "latest"], "plugins": [["transform-runtime"]] }
Inside of package.json "scripts"
: "build": "babel src -d lib"
Build with npm run build
.
注意:这假设您使用的是 Node ~6.3.1。您可以使用 nvm
到 install/set 节点版本。
您需要花时间确保您 100% 熟悉回调,然后学习承诺,然后研究 async/await
和 babel
的工作原理。真正习惯这一切需要一点时间。
我正在尝试创建一个通知应用程序,首先是我的代码:
function sendNotification(messageUser, messageText, messageDepartment, messageTopic, userIDs) {
var userAndroid = [];
var userIOS = [];
var userDevice;
console.log(userIDs);
for (var i = 0; i < userIDs.length; i++) {
searchRegisterDevices(userIDs[i], function(result) {
if (result) {
for (var j = 0; j < result.length; j++) {
userDevice = {platform: result[j].platform, token: result[j].token};
if (userDevice.platform == 'android') {
userAndroid.push(userDevice);
} else {
userIOS.push(userDevice);
}
}
} else {
console.log("ERROR");
}
});
}
console.log(userAndroid);
if (userAndroid.length > 0) {
}
我的问题是,当我 "for looping" 收集我的设备时,我的代码继续发送部分并失败,因为 userAndroid 是空的。正如他们所说,我该怎么做才能解决这个回调地狱?我需要等到我的 for 循环完成,然后继续发送消息。如有任何帮助,我们将不胜感激!
这里的问题是您在 for 循环中执行异步请求,而不处理异步。您正在混合同步 for
循环和(大概)异步 searchRegisterDevices
。您的循环变量将继续增加,直到达到极限。所以,当你的回调函数从事件堆栈中弹出时,userIDs[i]
的值是 userIDs[userIDs.length]
,感谢 lexical scoping of javascript variables
这里你需要做的是这三者之一patterns:
使用 IIFE 创建您自己的函数闭包
var j = 10;
for (var i = 0; i < j; i++) {
(function(cntr) {
// here the value of i was passed into as the argument cntr
// and will be captured in this function closure so each
// iteration of the loop can have it's own value
asychronousProcess(function() {
console.log(cntr);
});
})(i);
}
创建或修改外部函数并将变量传递给它
如果您可以修改 asychronousProcess() 函数,那么您可以只在其中传递值,然后让 asychronousProcess() 函数 cntr 像这样返回回调:
var j = 10;
for (var i = 0; i < j; i++) {
asychronousProcess(i, function(cntr) {
console.log(cntr);
});
}
使用 ES6 让
如果你有一个 Javascript 完全支持 ES6 的执行环境,你可以像这样在 for 循环中使用 let:
const j = 10;
for (let i = 0; i < j; i++) {
asychronousProcess(function() {
console.log(i);
});
}
这里当然是asychronousProcess
代表你的searchRegisterDevices
服务调用。
以下是我使用 babel
和更新的 JS 语法的方法:
import rfpify from 'rfpify';
const findDevice = rfpify(searchRegisteredDevices);
async function sendNotification({message, toUserIDs}) {
let devices = await Promise.all(toUserIDs.map(id=>findDevice(id)));
devices = devices.map( ({platform,token}) => { return {platform,token} } );
const androidUsers = devices.filter(d => d && d.platform == 'android');
const iOSUsers = devices.filter(d => d && d.platform != 'android');
return {message, androidUsers, iOSUsers};
}
设置babel
和rfpify
:npm i -S rfpify; npm i -D babel-cli babel-preset-latest babel-plugin-transform-runtime
。创建代码所在的 src
和 lib
用于输出程序,您 运行 和 node
。将其放入 .babelrc: { "presets": [ "latest"], "plugins": [["transform-runtime"]] }
Inside of package.json "scripts"
: "build": "babel src -d lib"
Build with npm run build
.
注意:这假设您使用的是 Node ~6.3.1。您可以使用 nvm
到 install/set 节点版本。
您需要花时间确保您 100% 熟悉回调,然后学习承诺,然后研究 async/await
和 babel
的工作原理。真正习惯这一切需要一点时间。