如何修复我的代码回调恐怖

时间:2016-09-24 21:59:47

标签: javascript angularjs node.js callback google-cloud-messaging

我正在尝试创建一个通知应用程序,这是我的代码:



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) { 
   }
&#13;
&#13;
&#13;

我的问题是,虽然我是&#34;用于循环&#34;收集我的设备,我的代码继续发送到发送部分并因为userAndroid为空而失败。我可以做些什么来修复这个回调地狱呢?我需要等到我的for循环完成后再继续发送消息。任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:0)

这里的问题是您在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让

如果您有一个完全支持ES6的Javascript执行环境,您可以在for循环中使用let,如下所示:

const j = 10;
for (let i = 0; i < j; i++) {
    asychronousProcess(function() {
        console.log(i);
    });
}

当然,asychronousProcess代表您的searchRegisterDevices服务电话。

答案 1 :(得分:0)

以下是我将如何使用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};
}

设置babelrfpifynpm i -S rfpify; npm i -D babel-cli babel-preset-latest babel-plugin-transform-runtime。为代码运行创建src,为lib运行的输出程序创建node。把它放在.babelrc中:{ "presets": [ "latest"], "plugins": [["transform-runtime"]] }在package.json "scripts"内:"build": "babel src -d lib"使用npm run build构建。

注意:这假设您在Node~6.3.1上。您可以使用nvm来安装/设置节点版本。

您需要花时间确保自己100%熟悉回调,然后学习承诺,然后研究async/awaitbabel的工作原理。要真正习惯这一切需要一些时间。