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

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};
}

设置babelrfpifynpm i -S rfpify; npm i -D babel-cli babel-preset-latest babel-plugin-transform-runtime。创建代码所在的 srclib 用于输出程序,您 运行 和 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/awaitbabel 的工作原理。真正习惯这一切需要一点时间。